on master help sign in
CHANGELOG.md+67
since splitsnapshots
unifiedsplit
@@ -1,4 +1,71 @@
1
1
2+5.35.1
3+------
4+
5+Bug fixes:
6+ * Fixed a build issue with a test program.
7+
8+5.35
9+----
10+
11+New features:
12+ * Add support for 24-bit color (thanks @u-quark). This change
13+ updates Vty to look at the `COLORTERM` environment variable that is
14+ conventionally used to advertise support for truecolor escape
15+ sequences. The change also updates the Vty demo to demonstrate
16+ 24-bit colors. This change also adds a new data type, `ColorMode`,
17+ to represent the color mode in use, as well as an `Output` interface
18+ field, `outputColorMode`, to track the active color mode and use it
19+ to clamp emitted color escape sequences to the active color range.
20+
21+API changes:
22+ * All types in `Graphics.Vty.Input.Events` now have strict constructor
23+ fields.
24+ * Internal events are now wrapped in a new `InternalEvent` type to
25+ improve how signal handling is done. This change modifies the `Input`
26+ type's event channel API to produce `InternalEvents`, not `Events`.
27+ The new `InternalEvent` either wraps `Event` with the `InputEvent`
28+ constructor (the previous behavior) or indicates that Vty resumed
29+ after handling a signal using the `ResumeAfterSignal` constructor.
30+ This change avoids the previous use of `EvResize` with lazy exception
31+ arguments as a sentinel value for `ResumeAfterSignal`.
32+
33+Other enhancements:
34+ * Bracketed paste parsing performance has been greatly improved thanks
35+ to benchmarking and optimization work by @iphydf. As part of that
36+ work, Vty now uses bytestrings rather than Strings internally when
37+ parsing input to look for events.
38+ * The `\b` value is now interpreted as `KBS` (thanks @vglfr)
39+
40+5.34
41+----
42+
43+API changes:
44+ * Added an `NFData` instance for `Event` (thanks Mario Lang)
45+ * Removed `Monoid` and `Semigroup` instances for `Attr` and
46+ `MaybeDefault`. This change removed the instances because they were
47+ misbehaved; merging `Attr` and `MaybeDefault` values with these
48+ instances resulted in field value losses. For example, before this
49+ change,
50+```
51+(defAttr `withForeColor` blue) <> (defAttr `withBackColor` green)
52+```
53+ would result in just
54+```
55+ (defAttr `withBackColor` green)
56+```
57+ because the instances were designed to favor the right-hand
58+ arguments' fields even if they had not been explicitly set
59+ (a consequence of the `MaybeDefault` `Semigroup` instance).
60+ While that behavior was sensible specifically in the context of
61+ `Graphics.Vty.Inline`, it wasn't a useful user-facing API and it made
62+ for surprising instance behavior. Since there is actually no good way
63+ to handle this in a `Semigroup` instance for `Attr` -- some choices
64+ have to be made about how to merge two attributes' foreground colors,
65+ and that won't be much better than what we had -- the instance was
66+ just removed.
67+
68+
25.33
695.33
3----
70----
4
71
demos/Demo.hs+12−4
@@ -31,7 +31,8 @@ introText = vertCat $ map (string defAttr)
31 [ "this line is hidden by the top layer"
31 [ "this line is hidden by the top layer"
32 , "The vty demo program will echo the events generated by the pressed keys."
32 , "The vty demo program will echo the events generated by the pressed keys."
33 , "Below there is a 240 color box."
33 , "Below there is a 240 color box."
34− , "Followed by a description of the 16 color pallete."
34+ , "Followed by a description of the 16 color palette."
35+ , "Followed by tones of red using a 24-bit palette."
35 , "If the 240 color box is not visible then the terminal"
36 , "If the 240 color box is not visible then the terminal"
36 , "claims 240 colors are not supported."
37 , "claims 240 colors are not supported."
37 , "Try setting TERM to xterm-256color"
38 , "Try setting TERM to xterm-256color"
@@ -42,12 +43,19 @@ introText = vertCat $ map (string defAttr)
42 , "¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯"
43 , "¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯ ¯\\_(ツ)_/¯"
43 ]
44 ]
44
45
46+splitColorImages :: [Image] -> [[Image]]
47+splitColorImages [] = []
48+splitColorImages is = (take 20 is ++ [string defAttr " "]) : (splitColorImages (drop 20 is))
49+
50+fullcolorbox :: Image
51+fullcolorbox = vertCat $ map horizCat $ splitColorImages colorImages
52+ where
53+ colorImages = map (\i -> string (currentAttr `withBackColor` linearColor i 0 0) " ") [0..255]
54+
45colorbox_240 :: Image
55colorbox_240 :: Image
46colorbox_240 = vertCat $ map horizCat $ splitColorImages colorImages
56colorbox_240 = vertCat $ map horizCat $ splitColorImages colorImages
47 where
57 where
48 colorImages = map (\i -> string (currentAttr `withBackColor` Color240 i) " ") [0..239]
58 colorImages = map (\i -> string (currentAttr `withBackColor` Color240 i) " ") [0..239]
49− splitColorImages [] = []
50− splitColorImages is = (take 20 is ++ [string defAttr " "]) : (splitColorImages (drop 20 is))
51
59
52colorbox_16 :: Image
60colorbox_16 :: Image
53colorbox_16 = border <|> column0 <|> border <|> column1 <|> border <|> column2 <|> border
61colorbox_16 = border <|> column0 <|> border <|> column1 <|> border <|> column2 <|> border
@@ -70,7 +78,7 @@ updateDisplay = do
70 "Press ESC to exit. Events for keys below."
78 "Press ESC to exit. Events for keys below."
71 eventLog <- foldMap (string defAttr) <$> get
79 eventLog <- foldMap (string defAttr) <$> get
72 let pic = picForImage (info <-> eventLog)
80 let pic = picForImage (info <-> eventLog)
73− `addToBottom` (introText <-> colorbox_240 <|> colorbox_16)
81+ `addToBottom` (introText <-> colorbox_240 <|> colorbox_16 <|> fullcolorbox)
74 vty <- ask
82 vty <- ask
75 liftIO $ update vty pic
83 liftIO $ update vty pic
76
84
src/Data/Terminfo/Parse.hs+2−1
@@ -1,8 +1,9 @@
1{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-}
2{-# LANGUAGE CPP #-}
3−{-# OPTIONS_HADDOCK hide #-}
4{-# LANGUAGE NoMonomorphismRestriction #-}
3{-# LANGUAGE NoMonomorphismRestriction #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
5{-# OPTIONS_GHC -funbox-strict-fields -O #-}
5{-# OPTIONS_GHC -funbox-strict-fields -O #-}
6+{-# OPTIONS_HADDOCK hide #-}
6
7
7module Data.Terminfo.Parse
8module Data.Terminfo.Parse
8 ( module Data.Terminfo.Parse
9 ( module Data.Terminfo.Parse
src/Graphics/Vty.hs+12−8
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
2
3
3-- | Vty provides interfaces for both terminal input and terminal
4-- | Vty provides interfaces for both terminal input and terminal
4-- output.
5-- output.
@@ -47,6 +48,7 @@ where
47
48
48import Graphics.Vty.Config
49import Graphics.Vty.Config
49import Graphics.Vty.Input
50import Graphics.Vty.Input
51+import Graphics.Vty.Input.Events
50import Graphics.Vty.Output
52import Graphics.Vty.Output
51import Graphics.Vty.Output.Interface
53import Graphics.Vty.Output.Interface
52import Graphics.Vty.Picture
54import Graphics.Vty.Picture
@@ -208,16 +210,18 @@ internalMkVty input out = do
208 maybe (return ()) innerUpdate mPic
210 maybe (return ()) innerUpdate mPic
209
211
210 let mkResize = uncurry EvResize <$> displayBounds out
212 let mkResize = uncurry EvResize <$> displayBounds out
213+
214+ translateInternalEvent ResumeAfterSignal = mkResize
215+ translateInternalEvent (InputEvent e) = return e
216+
211 gkey = do
217 gkey = do
212− k <- atomically $ readTChan $ _eventChannel input
218+ e <- atomically $ readTChan $ _eventChannel input
213− case k of
219+ translateInternalEvent e
214− (EvResize _ _) -> mkResize
215− _ -> return k
216 gkey' = do
220 gkey' = do
217− k <- atomically $ tryReadTChan $ _eventChannel input
221+ mEv <- atomically $ tryReadTChan $ _eventChannel input
218− case k of
222+ case mEv of
219− (Just (EvResize _ _)) -> Just <$> mkResize
223+ Just e -> Just <$> translateInternalEvent e
220− _ -> return k
224+ Nothing -> return Nothing
221
225
222 return $ Vty { update = innerUpdate
226 return $ Vty { update = innerUpdate
223 , nextEvent = gkey
227 , nextEvent = gkey
src/Graphics/Vty/Attributes.hs−27
@@ -61,9 +61,6 @@ where
61
61
62import Control.DeepSeq
62import Control.DeepSeq
63import Data.Bits
63import Data.Bits
64−#if !(MIN_VERSION_base(4,11,0))
65−import Data.Semigroup
66−#endif
67import Data.Text (Text)
64import Data.Text (Text)
68import Data.Word
65import Data.Word
69import GHC.Generics
66import GHC.Generics
@@ -116,19 +113,6 @@ data Attr = Attr
116-- Then the foreground color encoded into 8 bits.
113-- Then the foreground color encoded into 8 bits.
117-- Then the background color encoded into 8 bits.
114-- Then the background color encoded into 8 bits.
118
115
119−instance Semigroup Attr where
120− attr0 <> attr1 =
121− Attr ( attrStyle attr0 <> attrStyle attr1 )
122− ( attrForeColor attr0 <> attrForeColor attr1 )
123− ( attrBackColor attr0 <> attrBackColor attr1 )
124− ( attrURL attr0 <> attrURL attr1 )
125−
126−instance Monoid Attr where
127− mempty = Attr mempty mempty mempty mempty
128−#if !(MIN_VERSION_base(4,11,0))
129− mappend = (<>)
130−#endif
131−
132-- | Specifies the display attributes such that the final style and
116-- | Specifies the display attributes such that the final style and
133-- color values do not depend on the previously applied display
117-- color values do not depend on the previously applied display
134-- attribute. The display attributes can still depend on the terminal's
118-- attribute. The display attributes can still depend on the terminal's
@@ -151,17 +135,6 @@ instance (NFData v) => NFData (MaybeDefault v) where
151 rnf KeepCurrent = ()
135 rnf KeepCurrent = ()
152 rnf (SetTo v) = rnf v
136 rnf (SetTo v) = rnf v
153
137
154−instance Semigroup (MaybeDefault v) where
155− _ <> v@(SetTo _) = v
156− x <> KeepCurrent = x
157− _ <> Default = Default
158−
159−instance Monoid ( MaybeDefault v ) where
160− mempty = KeepCurrent
161−#if !(MIN_VERSION_base(4,11,0))
162− mappend = (<>)
163−#endif
164−
165-- | Styles are represented as an 8 bit word. Each bit in the word is 1
138-- | Styles are represented as an 8 bit word. Each bit in the word is 1
166-- if the style attribute assigned to that bit should be applied and 0
139-- if the style attribute assigned to that bit should be applied and 0
167-- if the style attribute should not be applied.
140-- if the style attribute should not be applied.
src/Graphics/Vty/Attributes/Color.hs+67−3
@@ -1,8 +1,14 @@
1{-# LANGUAGE DeriveGeneric #-}
1{-# LANGUAGE DeriveGeneric #-}
2{-# LANGUAGE DeriveAnyClass #-}
2{-# LANGUAGE DeriveAnyClass #-}
3+{-# LANGUAGE MultiWayIf #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
3
5
4module Graphics.Vty.Attributes.Color
6module Graphics.Vty.Attributes.Color
5 ( Color(..)
7 ( Color(..)
8+ , ColorMode(..)
9+
10+ -- * Detecting Terminal Color Support
11+ , detectColorMode
6
12
7 -- ** Fixed Colors
13 -- ** Fixed Colors
8 -- | Standard 8-color ANSI terminal color codes.
14 -- | Standard 8-color ANSI terminal color codes.
@@ -32,7 +38,10 @@ module Graphics.Vty.Attributes.Color
32 , brightCyan
38 , brightCyan
33 , brightWhite
39 , brightWhite
34 -- ** Creating Colors From RGB
40 -- ** Creating Colors From RGB
41+ , linearColor
42+ , srgbColor
35 , rgbColor
43 , rgbColor
44+ , color240
36 , module Graphics.Vty.Attributes.Color240
45 , module Graphics.Vty.Attributes.Color240
37 )
46 )
38where
47where
@@ -40,6 +49,11 @@ where
40import Data.Word
49import Data.Word
41import GHC.Generics
50import GHC.Generics
42import Control.DeepSeq
51import Control.DeepSeq
52+import System.Environment (lookupEnv)
53+
54+import qualified System.Console.Terminfo as Terminfo
55+import Control.Exception (catch)
56+import Data.Maybe
43
57
44import Graphics.Vty.Attributes.Color240
58import Graphics.Vty.Attributes.Color240
45
59
@@ -81,7 +95,7 @@ import Graphics.Vty.Attributes.Color240
81-- reported then the color reproduction will be incorrect.
95-- reported then the color reproduction will be incorrect.
82--
96--
83-- If the terminal reports <= 16 colors then the 240 color palette
97-- If the terminal reports <= 16 colors then the 240 color palette
84−-- points are only mapped to the 8 color pallete. I'm not sure of
98+-- points are only mapped to the 8 color palette. I'm not sure of
85-- the RGB points for the "bright" colors which is why they are not
99-- the RGB points for the "bright" colors which is why they are not
86-- addressable via the 240 color palette.
100-- addressable via the 240 color palette.
87--
101--
@@ -95,9 +109,33 @@ import Graphics.Vty.Attributes.Color240
95-- terminfo but I don't know it.
109-- terminfo but I don't know it.
96--
110--
97-- Seriously, terminal color support is INSANE.
111-- Seriously, terminal color support is INSANE.
98−data Color = ISOColor !Word8 | Color240 !Word8
112+data Color = ISOColor !Word8 | Color240 !Word8 | RGBColor !Word8 !Word8 !Word8
99 deriving ( Eq, Show, Read, Generic, NFData )
113 deriving ( Eq, Show, Read, Generic, NFData )
100
114
115+data ColorMode
116+ = NoColor
117+ | ColorMode8
118+ | ColorMode16
119+ | ColorMode240 !Word8
120+ | FullColor
121+ deriving ( Eq, Show )
122+
123+detectColorMode :: String -> IO ColorMode
124+detectColorMode termName' = do
125+ term <- catch (Just <$> Terminfo.setupTerm termName')
126+ (\(_ :: Terminfo.SetupTermError) -> return Nothing)
127+ let getCap cap = term >>= \t -> Terminfo.getCapability t cap
128+ termColors = fromMaybe 0 $ getCap (Terminfo.tiGetNum "colors")
129+ colorterm <- lookupEnv "COLORTERM"
130+ return $ if
131+ | termColors < 8 -> NoColor
132+ | termColors < 16 -> ColorMode8
133+ | termColors == 16 -> ColorMode16
134+ | termColors < 256 -> ColorMode240 (fromIntegral termColors - 16)
135+ | colorterm == Just "truecolor" -> FullColor
136+ | colorterm == Just "24bit" -> FullColor
137+ | otherwise -> ColorMode240 240
138+
101black, red, green, yellow, blue, magenta, cyan, white :: Color
139black, red, green, yellow, blue, magenta, cyan, white :: Color
102black = ISOColor 0
140black = ISOColor 0
103red = ISOColor 1
141red = ISOColor 1
@@ -119,9 +157,35 @@ brightMagenta= ISOColor 13
119brightCyan = ISOColor 14
157brightCyan = ISOColor 14
120brightWhite = ISOColor 15
158brightWhite = ISOColor 15
121
159
160+linearColor :: Integral i => i -> i -> i -> Color
161+linearColor r g b = RGBColor r' g' b'
162+ where
163+ r' = fromIntegral (clamp r) :: Word8
164+ g' = fromIntegral (clamp g) :: Word8
165+ b' = fromIntegral (clamp b) :: Word8
166+ clamp = min 255 . max 0
167+
168+srgbColor :: Integral i => i -> i -> i -> Color
169+srgbColor r g b =
170+ -- srgb to rgb transformation as described at
171+ -- https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
172+ --
173+ -- TODO: it may be worth translating this to a lookup table, as with color240
174+ let shrink n = fromIntegral n / 255 :: Double
175+ -- called gamma^-1 in wiki
176+ gamma u
177+ | u <= 0.04045 = u/12.92
178+ | otherwise = ((u + 0.055) / 1.055) ** 2.4
179+ -- TODO: this is a slightly inaccurate conversion. is it worth doing proterly?
180+ expand n = round (255 * n)
181+ convert = expand . gamma . shrink
182+ in RGBColor (convert r) (convert g) (convert b)
183+
184+color240 :: Integral i => i -> i -> i -> Color
185+color240 r g b = Color240 (rgbColorToColor240 r g b)
122
186
123-- | Create a Vty 'Color' (in the 240 color set) from an RGB triple.
187-- | Create a Vty 'Color' (in the 240 color set) from an RGB triple.
124-- This function is lossy in the sense that we only internally support 240 colors but the
188-- This function is lossy in the sense that we only internally support 240 colors but the
125-- #RRGGBB format supports 16^3 colors.
189-- #RRGGBB format supports 16^3 colors.
126rgbColor :: Integral i => i -> i -> i -> Color
190rgbColor :: Integral i => i -> i -> i -> Color
127−rgbColor r g b = Color240 (rgbColorToColor240 r g b)
191+rgbColor = color240
src/Graphics/Vty/Config.hs+11−2
@@ -3,6 +3,7 @@
3{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
3{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE LambdaCase, MultiWayIf #-}
6-- | Vty supports a configuration file format and associated 'Config'
7-- | Vty supports a configuration file format and associated 'Config'
7-- data type. The 'Config' can be provided to 'mkVty' to customize the
8-- data type. The 'Config' can be provided to 'mkVty' to customize the
8-- application's use of Vty.
9-- application's use of Vty.
@@ -54,7 +55,7 @@
54-- If a debug log is requested then vty will output the current input
55-- If a debug log is requested then vty will output the current input
55-- table to the log in the above format. A workflow for using this is
56-- table to the log in the above format. A workflow for using this is
56-- to set @VTY_DEBUG_LOG@. Run the application. Check the debug log for
57-- to set @VTY_DEBUG_LOG@. Run the application. Check the debug log for
57−-- incorrect mappings. Add corrected mappings to @$HOME/.vty/config@.
58+-- incorrect mappings. Add corrected mappings to @$HOME\/.vty\/config@.
58--
59--
59-- = Unicode Character Width Maps
60-- = Unicode Character Width Maps
60--
61--
@@ -122,6 +123,7 @@ import Data.Semigroup (Semigroup(..))
122import Data.Typeable (Typeable)
123import Data.Typeable (Typeable)
123
124
124import Graphics.Vty.Input.Events
125import Graphics.Vty.Input.Events
126+import Graphics.Vty.Attributes.Color (ColorMode(..), detectColorMode)
125
127
126import GHC.Generics
128import GHC.Generics
127
129
@@ -193,6 +195,9 @@ data Config =
193 -- configuration specifies one. If no custom table is loaded
195 -- configuration specifies one. If no custom table is loaded
194 -- (or if a load fails), the built-in character width table
196 -- (or if a load fails), the built-in character width table
195 -- will be used.
197 -- will be used.
198+ , colorMode :: Maybe ColorMode
199+ -- ^ The color mode used to know how many colors the terminal
200+ -- supports.
196 }
201 }
197 deriving (Show, Eq)
202 deriving (Show, Eq)
198
203
@@ -214,6 +219,7 @@ instance Semigroup Config where
214 , termWidthMaps = termWidthMaps c1 <|> termWidthMaps c0
219 , termWidthMaps = termWidthMaps c1 <|> termWidthMaps c0
215 , allowCustomUnicodeWidthTables =
220 , allowCustomUnicodeWidthTables =
216 allowCustomUnicodeWidthTables c1 <|> allowCustomUnicodeWidthTables c0
221 allowCustomUnicodeWidthTables c1 <|> allowCustomUnicodeWidthTables c0
222+ , colorMode = colorMode c1 <|> colorMode c0
217 }
223 }
218
224
219instance Monoid Config where
225instance Monoid Config where
@@ -229,6 +235,7 @@ instance Monoid Config where
229 , termName = Nothing
235 , termName = Nothing
230 , termWidthMaps = []
236 , termWidthMaps = []
231 , allowCustomUnicodeWidthTables = Nothing
237 , allowCustomUnicodeWidthTables = Nothing
238+ , colorMode = Nothing
232 }
239 }
233#if !(MIN_VERSION_base(4,11,0))
240#if !(MIN_VERSION_base(4,11,0))
234 mappend = (<>)
241 mappend = (<>)
@@ -284,7 +291,8 @@ standardIOConfig = do
284 mb <- lookupEnv termVariable
291 mb <- lookupEnv termVariable
285 case mb of
292 case mb of
286 Nothing -> throwIO VtyMissingTermEnvVar
293 Nothing -> throwIO VtyMissingTermEnvVar
287− Just t ->
294+ Just t -> do
295+ mcolorMode <- detectColorMode t
288 return defaultConfig
296 return defaultConfig
289 { vmin = Just 1
297 { vmin = Just 1
290 , mouseMode = Just False
298 , mouseMode = Just False
@@ -293,6 +301,7 @@ standardIOConfig = do
293 , inputFd = Just stdInput
301 , inputFd = Just stdInput
294 , outputFd = Just stdOutput
302 , outputFd = Just stdOutput
295 , termName = Just t
303 , termName = Just t
304+ , colorMode = Just mcolorMode
296 }
305 }
297
306
298parseConfigFile :: FilePath -> IO Config
307parseConfigFile :: FilePath -> IO Config
src/Graphics/Vty/Image.hs+1−1
@@ -137,7 +137,7 @@ char a c =
137 let displayWidth = safeWcwidth c
137 let displayWidth = safeWcwidth c
138 in HorizText a (TL.singleton c) displayWidth 1
138 in HorizText a (TL.singleton c) displayWidth 1
139
139
140−-- | Make an image from a string of characters layed out on a single
140+-- | Make an image from a string of characters laid out on a single
141-- row with the same display attribute. The string is assumed to be a
141-- row with the same display attribute. The string is assumed to be a
142-- sequence of ISO-10646 characters. The input string should be
142-- sequence of ISO-10646 characters. The input string should be
143-- sanitized of escape sequences (ASCII 27) and carriage returns;
143-- sanitized of escape sequences (ASCII 27) and carriage returns;
src/Graphics/Vty/Image/Internal.hs+2−2
@@ -228,7 +228,7 @@ instance Monoid Image where
228--
228--
229-- The result image will have a width equal to the sum of the two images
229-- The result image will have a width equal to the sum of the two images
230-- width. And the height will equal the largest height of the two
230-- width. And the height will equal the largest height of the two
231−-- images. The area not defined in one image due to a height missmatch
231+-- images. The area not defined in one image due to a height mismatch
232-- will be filled with the background pattern.
232-- will be filled with the background pattern.
233horizJoin :: Image -> Image -> Image
233horizJoin :: Image -> Image -> Image
234horizJoin EmptyImage i = i
234horizJoin EmptyImage i = i
@@ -259,7 +259,7 @@ horizJoin _ _ = error "horizJoin applied to undefined values."
259--
259--
260-- The result image will have a height equal to the sum of the heights
260-- The result image will have a height equal to the sum of the heights
261-- of both images. The width will equal the largest width of the two
261-- of both images. The width will equal the largest width of the two
262−-- images. The area not defined in one image due to a width missmatch
262+-- images. The area not defined in one image due to a width mismatch
263-- will be filled with the background pattern.
263-- will be filled with the background pattern.
264vertJoin :: Image -> Image -> Image
264vertJoin :: Image -> Image -> Image
265vertJoin EmptyImage i = i
265vertJoin EmptyImage i = i
src/Graphics/Vty/Inline.hs+3−3
@@ -56,13 +56,13 @@ data InlineState =
56-- | Set the background color to the provided 'Color'.
56-- | Set the background color to the provided 'Color'.
57backColor :: Color -> InlineM ()
57backColor :: Color -> InlineM ()
58backColor c = modify $ \s ->
58backColor c = modify $ \s ->
59− s { inlineAttr = inlineAttr s `mappend` (currentAttr `withBackColor` c)
59+ s { inlineAttr = inlineAttr s `withBackColor` c
60 }
60 }
61
61
62-- | Set the foreground color to the provided 'Color'.
62-- | Set the foreground color to the provided 'Color'.
63foreColor :: Color -> InlineM ()
63foreColor :: Color -> InlineM ()
64foreColor c = modify $ \s ->
64foreColor c = modify $ \s ->
65− s { inlineAttr = inlineAttr s `mappend` (currentAttr `withForeColor` c)
65+ s { inlineAttr = inlineAttr s `withForeColor` c
66 }
66 }
67
67
68-- | Attempt to change the 'Style' of the following text..
68-- | Attempt to change the 'Style' of the following text..
@@ -71,7 +71,7 @@ foreColor c = modify $ \s ->
71-- produced. The style can still be removed.
71-- produced. The style can still be removed.
72applyStyle :: Style -> InlineM ()
72applyStyle :: Style -> InlineM ()
73applyStyle st = modify $ \s ->
73applyStyle st = modify $ \s ->
74− s { inlineAttr = inlineAttr s `mappend` (currentAttr `withStyle` st)
74+ s { inlineAttr = inlineAttr s `withStyle` st
75 }
75 }
76
76
77-- | Attempt to remove the specified 'Style' from the display of the
77-- | Attempt to remove the specified 'Style' from the display of the
src/Graphics/Vty/Input.hs+3−4
@@ -77,7 +77,7 @@
77-- The input encoding determines how UTF-8 encoded characters are
77-- The input encoding determines how UTF-8 encoded characters are
78-- recognized.
78-- recognized.
79--
79--
80−-- * 7-bit mode: UTF-8 can be input unambiguiously. UTF-8 input is
80+-- * 7-bit mode: UTF-8 can be input unambiguously. UTF-8 input is
81-- a superset of ASCII. UTF-8 does not overlap escaped control key
81-- a superset of ASCII. UTF-8 does not overlap escaped control key
82-- sequences. However, the escape key must be differentiated from
82-- sequences. However, the escape key must be differentiated from
83-- escaped control key sequences by the timing of the input bytes.
83-- escaped control key sequences by the timing of the input bytes.
@@ -95,7 +95,7 @@
95--
95--
96-- == Terminal Input is Broken
96-- == Terminal Input is Broken
97--
97--
98−-- Clearly terminal input has fundemental issues. There is no easy way
98+-- Clearly terminal input has fundamental issues. There is no easy way
99-- to reliably resolve these issues.
99-- to reliably resolve these issues.
100--
100--
101-- One resolution would be to ditch standard terminal interfaces
101-- One resolution would be to ditch standard terminal interfaces
@@ -158,9 +158,8 @@ inputForConfig config@Config{ termName = Just termName
158 setAttrs
158 setAttrs
159 input <- initInput config activeInputMap
159 input <- initInput config activeInputMap
160 let pokeIO = Catch $ do
160 let pokeIO = Catch $ do
161− let e = error "vty internal failure: this value should not propagate to users"
162 setAttrs
161 setAttrs
163− atomically $ writeTChan (input^.eventChannel) (EvResize e e)
162+ atomically $ writeTChan (input^.eventChannel) ResumeAfterSignal
164 _ <- installHandler windowChange pokeIO Nothing
163 _ <- installHandler windowChange pokeIO Nothing
165 _ <- installHandler continueProcess pokeIO Nothing
164 _ <- installHandler continueProcess pokeIO Nothing
166
165
src/Graphics/Vty/Input/Classify.hs+53−29
@@ -1,10 +1,11 @@
1{-# OPTIONS_HADDOCK hide #-}
1{-# OPTIONS_HADDOCK hide #-}
2−-- This makes a kind of tri. Has space efficiency issues with large
2+-- This makes a kind of trie. Has space efficiency issues with large
3-- input blocks. Likely building a parser and just applying that would
3-- input blocks. Likely building a parser and just applying that would
4-- be better.
4-- be better.
5module Graphics.Vty.Input.Classify
5module Graphics.Vty.Input.Classify
6 ( classify
6 ( classify
7 , KClass(..)
7 , KClass(..)
8+ , ClassifierState(..)
8 )
9 )
9where
10where
10
11
@@ -16,25 +17,39 @@ import Graphics.Vty.Input.Classify.Types
16
17
17import Codec.Binary.UTF8.Generic (decode)
18import Codec.Binary.UTF8.Generic (decode)
18
19
19−import Data.List (inits)
20+import Control.Arrow (first)
20import qualified Data.Map as M( fromList, lookup )
21import qualified Data.Map as M( fromList, lookup )
21import Data.Maybe ( mapMaybe )
22import Data.Maybe ( mapMaybe )
22import qualified Data.Set as S( fromList, member )
23import qualified Data.Set as S( fromList, member )
23
24
24−import Data.Char
25import Data.Word
25import Data.Word
26
26
27+import qualified Data.ByteString as BS
28+import qualified Data.ByteString.Char8 as BS8
29+import Data.ByteString.Char8 (ByteString)
30+
31+-- | Whether the classifier is currently processing a chunked format.
32+-- Currently, only bracketed pastes use this.
33+data ClassifierState
34+ = ClassifierStart
35+ -- ^ Not processing a chunked format.
36+ | ClassifierInChunk ByteString [ByteString]
37+ -- ^ Currently processing a chunked format. The initial chunk is in the
38+ -- first argument and a reversed remainder of the chunks is collected in
39+ -- the second argument. At the end of the processing, the chunks are
40+ -- reversed and concatenated with the final chunk.
41+
27−compile :: ClassifyMap -> String -> KClass
42+compile :: ClassifyMap -> ByteString -> KClass
28compile table = cl' where
43compile table = cl' where
29 -- take all prefixes and create a set of these
44 -- take all prefixes and create a set of these
30− prefixSet = S.fromList $ concatMap (init . inits . fst) table
45+ prefixSet = S.fromList $ concatMap (init . BS.inits . BS8.pack . fst) table
31 maxValidInputLength = maximum (map (length . fst) table)
46 maxValidInputLength = maximum (map (length . fst) table)
32− eventForInput = M.fromList table
47+ eventForInput = M.fromList $ map (first BS8.pack) table
33− cl' [] = Prefix
48+ cl' inputBlock | BS8.null inputBlock = Prefix
34 cl' inputBlock = case M.lookup inputBlock eventForInput of
49 cl' inputBlock = case M.lookup inputBlock eventForInput of
35 -- if the inputBlock is exactly what is expected for an
50 -- if the inputBlock is exactly what is expected for an
36 -- event then consume the whole block and return the event
51 -- event then consume the whole block and return the event
37− Just e -> Valid e []
52+ Just e -> Valid e BS8.empty
38 Nothing -> case S.member inputBlock prefixSet of
53 Nothing -> case S.member inputBlock prefixSet of
39 True -> Prefix
54 True -> Prefix
40 -- look up progressively smaller tails of the input
55 -- look up progressively smaller tails of the input
@@ -45,40 +60,49 @@ compile table = cl' where
45 -- H: There will always be one match. The prefixSet
60 -- H: There will always be one match. The prefixSet
46 -- contains, by definition, all prefixes of an event.
61 -- contains, by definition, all prefixes of an event.
47 False ->
62 False ->
48− let inputPrefixes = reverse $ take maxValidInputLength $ tail $ inits inputBlock
63+ let inputPrefixes = reverse . take maxValidInputLength . tail . BS8.inits $ inputBlock
49 in case mapMaybe (\s -> (,) s `fmap` M.lookup s eventForInput) inputPrefixes of
64 in case mapMaybe (\s -> (,) s `fmap` M.lookup s eventForInput) inputPrefixes of
50− (s,e) : _ -> Valid e (drop (length s) inputBlock)
65+ (s,e) : _ -> Valid e (BS8.drop (BS8.length s) inputBlock)
51 -- neither a prefix or a full event.
66 -- neither a prefix or a full event.
52 [] -> Invalid
67 [] -> Invalid
53
68
54−classify :: ClassifyMap -> String -> KClass
69+classify :: ClassifyMap -> ClassifierState -> ByteString -> KClass
55−classify table =
70+classify table = process
71+ where
56− let standardClassifier = compile table
72+ standardClassifier = compile table
73+
74+ process ClassifierStart s =
57− in \s -> case s of
75+ case BS.uncons s of
58− _ | bracketedPasteStarted s ->
76+ _ | bracketedPasteStarted s ->
77+ if bracketedPasteFinished s
78+ then parseBracketedPaste s
79+ else Chunk
80+ _ | isMouseEvent s -> classifyMouseEvent s
81+ _ | isFocusEvent s -> classifyFocusEvent s
82+ Just (c,cs) | c >= 0xC2 -> classifyUtf8 c cs
83+ _ -> standardClassifier s
84+
85+ process (ClassifierInChunk p ps) s | bracketedPasteStarted p =
59 if bracketedPasteFinished s
86 if bracketedPasteFinished s
60− then parseBracketedPaste s
87+ then parseBracketedPaste $ BS.concat $ p:reverse (s:ps)
61− else Prefix
88+ else Chunk
62− _ | isMouseEvent s -> classifyMouseEvent s
89+ process ClassifierInChunk{} _ = Invalid
63− _ | isFocusEvent s -> classifyFocusEvent s
64− c:cs | ord c >= 0xC2 -> classifyUtf8 c cs
65− _ -> standardClassifier s
66
90
67−classifyUtf8 :: Char -> String -> KClass
91+classifyUtf8 :: Word8 -> ByteString -> KClass
68classifyUtf8 c cs =
92classifyUtf8 c cs =
69− let n = utf8Length (ord c)
93+ let n = utf8Length c
70− (codepoint,rest) = splitAt n (c:cs)
94+ (codepoint,rest) = BS8.splitAt (n - 1) cs
71
95
72 codepoint8 :: [Word8]
96 codepoint8 :: [Word8]
73− codepoint8 = map (fromIntegral . ord) codepoint
97+ codepoint8 = c:BS.unpack codepoint
74
98
75 in case decode codepoint8 of
99 in case decode codepoint8 of
76− _ | n < length codepoint -> Prefix
100+ _ | n < BS.length codepoint + 1 -> Prefix
77− Just (unicodeChar, _) -> Valid (EvKey (KChar unicodeChar) []) rest
101+ Just (unicodeChar, _) -> Valid (EvKey (KChar unicodeChar) []) rest
78 -- something bad happened; just ignore and continue.
102 -- something bad happened; just ignore and continue.
79− Nothing -> Invalid
103+ Nothing -> Invalid
80
104
81−utf8Length :: (Num t, Ord a, Num a) => a -> t
105+utf8Length :: Word8 -> Int
82utf8Length c
106utf8Length c
83 | c < 0x80 = 1
107 | c < 0x80 = 1
84 | c < 0xE0 = 2
108 | c < 0xE0 = 2
src/Graphics/Vty/Input/Classify/Parse.hs+10−7
@@ -16,12 +16,15 @@ import Graphics.Vty.Input.Classify.Types
16import Control.Monad.Trans.Maybe
16import Control.Monad.Trans.Maybe
17import Control.Monad.State
17import Control.Monad.State
18
18
19+import qualified Data.ByteString.Char8 as BS8
20+import Data.ByteString.Char8 (ByteString)
21+
19−type Parser a = MaybeT (State String) a
22+type Parser a = MaybeT (State ByteString) a
20
23
21-- | Run a parser on a given input string. If the parser fails, return
24-- | Run a parser on a given input string. If the parser fails, return
22-- 'Invalid'. Otherwise return the valid event ('Valid') and the
25-- 'Invalid'. Otherwise return the valid event ('Valid') and the
23-- remaining unparsed characters.
26-- remaining unparsed characters.
24−runParser :: String -> Parser Event -> KClass
27+runParser :: ByteString -> Parser Event -> KClass
25runParser s parser =
28runParser s parser =
26 case runState (runMaybeT parser) s of
29 case runState (runMaybeT parser) s of
27 (Nothing, _) -> Invalid
30 (Nothing, _) -> Invalid
@@ -36,9 +39,9 @@ failParse = fail "invalid parse"
36-- return '123' and consume those characters.
39-- return '123' and consume those characters.
37readInt :: Parser Int
40readInt :: Parser Int
38readInt = do
41readInt = do
39− s <- get
42+ s <- BS8.unpack <$> get
40 case (reads :: ReadS Int) s of
43 case (reads :: ReadS Int) s of
41− [(i, rest)] -> put rest >> return i
44+ [(i, rest)] -> put (BS8.pack rest) >> return i
42 _ -> failParse
45 _ -> failParse
43
46
44-- | Read a character from the input stream. If one cannot be read (e.g.
47-- | Read a character from the input stream. If one cannot be read (e.g.
@@ -46,9 +49,9 @@ readInt = do
46readChar :: Parser Char
49readChar :: Parser Char
47readChar = do
50readChar = do
48 s <- get
51 s <- get
49− case s of
52+ case BS8.uncons s of
50− c:rest -> put rest >> return c
53+ Just (c,rest) -> put rest >> return c
51− _ -> failParse
54+ Nothing -> failParse
52
55
53-- | Read a character from the input stream and fail parsing if it is
56-- | Read a character from the input stream and fail parsing if it is
54-- not the specified character.
57-- not the specified character.
src/Graphics/Vty/Input/Classify/Types.hs+7−1
@@ -1,5 +1,6 @@
1-- | This module exports the input classification type to avoid import
1-- | This module exports the input classification type to avoid import
2-- cycles between other modules that need this.
2-- cycles between other modules that need this.
3+{-# LANGUAGE StrictData #-}
3module Graphics.Vty.Input.Classify.Types
4module Graphics.Vty.Input.Classify.Types
4 ( KClass(..)
5 ( KClass(..)
5 )
6 )
@@ -7,8 +8,10 @@ where
7
8
8import Graphics.Vty.Input.Events
9import Graphics.Vty.Input.Events
9
10
11+import Data.ByteString.Char8 (ByteString)
12+
10data KClass
13data KClass
11− = Valid Event String
14+ = Valid Event ByteString
12 -- ^ A valid event was parsed. Any unused characters from the input
15 -- ^ A valid event was parsed. Any unused characters from the input
13 -- stream are also provided.
16 -- stream are also provided.
14 | Invalid
17 | Invalid
@@ -16,4 +19,7 @@ data KClass
16 | Prefix
19 | Prefix
17 -- ^ The input characters form the prefix of a valid event character
20 -- ^ The input characters form the prefix of a valid event character
18 -- sequence.
21 -- sequence.
22+ | Chunk
23+ -- ^ The input characters are either start of a bracketed paste chunk
24+ -- or in the middle of a bracketed paste chunk.
19 deriving(Show, Eq)
25 deriving(Show, Eq)
src/Graphics/Vty/Input/Events.hs+15−6
@@ -1,4 +1,5 @@
1{-# Language DeriveGeneric #-}
1{-# Language DeriveGeneric #-}
2+{-# Language StrictData #-}
2module Graphics.Vty.Input.Events where
3module Graphics.Vty.Input.Events where
3
4
4import Control.DeepSeq
5import Control.DeepSeq
@@ -15,10 +16,10 @@ import GHC.Generics
15--
16--
16-- * Actually, support for most of these but KEsc, KChar, KBS, and
17-- * Actually, support for most of these but KEsc, KChar, KBS, and
17-- KEnter vary by terminal and keyboard.
18-- KEnter vary by terminal and keyboard.
18−data Key = KEsc | KChar Char | KBS | KEnter
19+data Key = KEsc | KChar {-# UNPACK #-} Char | KBS | KEnter
19 | KLeft | KRight | KUp | KDown
20 | KLeft | KRight | KUp | KDown
20 | KUpLeft | KUpRight | KDownLeft | KDownRight | KCenter
21 | KUpLeft | KUpRight | KDownLeft | KDownRight | KCenter
21− | KFun Int | KBackTab | KPrtScr | KPause | KIns
22+ | KFun {-# UNPACK #-} Int | KBackTab | KPrtScr | KPause | KIns
22 | KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu
23 | KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu
23 deriving (Eq,Show,Read,Ord,Generic)
24 deriving (Eq,Show,Read,Ord,Generic)
24
25
@@ -51,10 +52,8 @@ data Event
51 -- without specifying which one; in that case, Nothing is provided.
52 -- without specifying which one; in that case, Nothing is provided.
52 -- Otherwise Just the button released is included in the event.
53 -- Otherwise Just the button released is included in the event.
53 | EvResize Int Int
54 | EvResize Int Int
54− -- ^ If read from 'eventChannel' this is the size at the time of the
55+ -- The terminal window was resized and the size is provided in the
55− -- signal. If read from 'nextEvent' this is the size at the time the
56+ -- integer fields (width, height).
56− -- event was processed by Vty. Typically these are the same, but if
57− -- somebody is resizing the terminal quickly they can be different.
58 | EvPaste ByteString
57 | EvPaste ByteString
59 -- ^ A paste event occurs when a bracketed paste input sequence is
58 -- ^ A paste event occurs when a bracketed paste input sequence is
60 -- received. For terminals that support bracketed paste mode, these
59 -- received. For terminals that support bracketed paste mode, these
@@ -72,3 +71,13 @@ data Event
72instance NFData Event
71instance NFData Event
73
72
74type ClassifyMap = [(String,Event)]
73type ClassifyMap = [(String,Event)]
74+
75+-- | The type of internal events that drive the internal Vty event
76+-- dispatching to the application.
77+data InternalEvent =
78+ ResumeAfterSignal
79+ -- ^ Vty resumed operation after the process was interrupted with a
80+ -- signal. In practice this translates into a screen redraw in the
81+ -- input event loop.
82+ | InputEvent Event
83+ -- ^ An input event was received.
src/Graphics/Vty/Input/Focus.hs+15−13
@@ -11,30 +11,32 @@ import Graphics.Vty.Input.Classify.Types
11import Graphics.Vty.Input.Classify.Parse
11import Graphics.Vty.Input.Classify.Parse
12
12
13import Control.Monad.State
13import Control.Monad.State
14−import Data.List (isPrefixOf)
14+
15+import qualified Data.ByteString.Char8 as BS8
16+import Data.ByteString.Char8 (ByteString)
15
17
16-- | These sequences set xterm-based terminals to send focus event
18-- | These sequences set xterm-based terminals to send focus event
17-- sequences.
19-- sequences.
18−requestFocusEvents :: String
20+requestFocusEvents :: ByteString
19−requestFocusEvents = "\ESC[?1004h"
21+requestFocusEvents = BS8.pack "\ESC[?1004h"
20
22
21-- | These sequences disable focus events.
23-- | These sequences disable focus events.
22−disableFocusEvents :: String
24+disableFocusEvents :: ByteString
23−disableFocusEvents = "\ESC[?1004l"
25+disableFocusEvents = BS8.pack "\ESC[?1004l"
24
26
25-- | Does the specified string begin with a focus event?
27-- | Does the specified string begin with a focus event?
26−isFocusEvent :: String -> Bool
28+isFocusEvent :: ByteString -> Bool
27−isFocusEvent s = isPrefixOf focusIn s ||
29+isFocusEvent s = BS8.isPrefixOf focusIn s ||
28− isPrefixOf focusOut s
30+ BS8.isPrefixOf focusOut s
29
31
30−focusIn :: String
32+focusIn :: ByteString
31−focusIn = "\ESC[I"
33+focusIn = BS8.pack "\ESC[I"
32
34
33−focusOut :: String
35+focusOut :: ByteString
34−focusOut = "\ESC[O"
36+focusOut = BS8.pack "\ESC[O"
35
37
36-- | Attempt to classify an input string as a focus event.
38-- | Attempt to classify an input string as a focus event.
37−classifyFocusEvent :: String -> KClass
39+classifyFocusEvent :: ByteString -> KClass
38classifyFocusEvent s = runParser s $ do
40classifyFocusEvent s = runParser s $ do
39 when (not $ isFocusEvent s) failParse
41 when (not $ isFocusEvent s) failParse
40
42
src/Graphics/Vty/Input/Loop.hs+41−22
@@ -1,8 +1,9 @@
1−{-# LANGUAGE RecordWildCards #-}
1+{-# LANGUAGE CPP #-}
2−{-# OPTIONS_HADDOCK hide #-}
3{-# LANGUAGE NoMonomorphismRestriction #-}
2{-# LANGUAGE NoMonomorphismRestriction #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE TemplateHaskell #-}
5{-# LANGUAGE TemplateHaskell #-}
5−{-# LANGUAGE CPP #-}
6+{-# OPTIONS_HADDOCK hide #-}
6-- | The input layer used to be a single function that correctly
7-- | The input layer used to be a single function that correctly
7-- accounted for the non-threaded runtime by emulating the terminal
8-- accounted for the non-threaded runtime by emulating the terminal
8-- VMIN adn VTIME handling. This has been removed and replace with a
9-- VMIN adn VTIME handling. This has been removed and replace with a
@@ -33,12 +34,15 @@ import Control.Monad.Trans.State (StateT(..), evalStateT)
33import Control.Monad.State.Class (MonadState, modify)
34import Control.Monad.State.Class (MonadState, modify)
34import Control.Monad.Trans.Reader (ReaderT(..))
35import Control.Monad.Trans.Reader (ReaderT(..))
35
36
36−import Data.Char
37+import qualified Data.ByteString.Char8 as BS8
38+import qualified Data.ByteString as BS
39+import Data.ByteString.Char8 (ByteString)
37import Data.IORef
40import Data.IORef
38import Data.Word (Word8)
41import Data.Word (Word8)
39
42
40−import Foreign ( allocaArray, peekArray, Ptr )
43+import Foreign (allocaArray)
41import Foreign.C.Types (CInt(..))
44import Foreign.C.Types (CInt(..))
45+import Foreign.Ptr (Ptr, castPtr)
42
46
43import System.IO
47import System.IO
44import System.Posix.IO (fdReadBuf, setFdOption, FdOption(..))
48import System.Posix.IO (fdReadBuf, setFdOption, FdOption(..))
@@ -51,7 +55,7 @@ data Input = Input
51 { -- | Channel of events direct from input processing. Unlike
55 { -- | Channel of events direct from input processing. Unlike
52 -- 'nextEvent' this will not refresh the display if the next event
56 -- 'nextEvent' this will not refresh the display if the next event
53 -- is an 'EvResize'.
57 -- is an 'EvResize'.
54− _eventChannel :: TChan Event
58+ _eventChannel :: TChan InternalEvent
55 -- | Shuts down the input processing. As part of shutting down the
59 -- | Shuts down the input processing. As part of shutting down the
56 -- input, this should also restore the input state.
60 -- input, this should also restore the input state.
57 , shutdownInput :: IO ()
61 , shutdownInput :: IO ()
@@ -76,10 +80,11 @@ data InputBuffer = InputBuffer
76makeLenses ''InputBuffer
80makeLenses ''InputBuffer
77
81
78data InputState = InputState
82data InputState = InputState
79− { _unprocessedBytes :: String
83+ { _unprocessedBytes :: ByteString
84+ , _classifierState :: ClassifierState
80 , _appliedConfig :: Config
85 , _appliedConfig :: Config
81 , _inputBuffer :: InputBuffer
86 , _inputBuffer :: InputBuffer
82− , _classifier :: String -> KClass
87+ , _classifier :: ClassifierState -> ByteString -> KClass
83 }
88 }
84
89
85makeLenses ''InputState
90makeLenses ''InputState
@@ -104,20 +109,20 @@ loopInputProcessor = do
104 dropInvalid
109 dropInvalid
105 loopInputProcessor
110 loopInputProcessor
106
111
107−addBytesToProcess :: String -> InputM ()
112+addBytesToProcess :: ByteString -> InputM ()
108addBytesToProcess block = unprocessedBytes <>= block
113addBytesToProcess block = unprocessedBytes <>= block
109
114
110emit :: Event -> InputM ()
115emit :: Event -> InputM ()
111emit event = do
116emit event = do
112 logMsg $ "parsed event: " ++ show event
117 logMsg $ "parsed event: " ++ show event
113− view eventChannel >>= liftIO . atomically . flip writeTChan event
118+ view eventChannel >>= liftIO . atomically . flip writeTChan (InputEvent event)
114
119
115-- The timing requirements are assured by the VMIN and VTIME set for the
120-- The timing requirements are assured by the VMIN and VTIME set for the
116-- device.
121-- device.
117--
122--
118-- Precondition: Under the threaded runtime. Only current use is from a
123-- Precondition: Under the threaded runtime. Only current use is from a
119-- forkOS thread. That case satisfies precondition.
124-- forkOS thread. That case satisfies precondition.
120−readFromDevice :: InputM String
125+readFromDevice :: InputM ByteString
121readFromDevice = do
126readFromDevice = do
122 newConfig <- view configRef >>= liftIO . readIORef
127 newConfig <- view configRef >>= liftIO . readIORef
123 oldConfig <- use appliedConfig
128 oldConfig <- use appliedConfig
@@ -137,9 +142,10 @@ readFromDevice = do
137 threadWaitRead fd
142 threadWaitRead fd
138 bytesRead <- fdReadBuf fd bufferPtr (fromIntegral maxBytes)
143 bytesRead <- fdReadBuf fd bufferPtr (fromIntegral maxBytes)
139 if bytesRead > 0
144 if bytesRead > 0
140− then map (chr . fromIntegral) <$> peekArray (fromIntegral bytesRead) bufferPtr
145+ then BS.packCStringLen (castPtr bufferPtr, fromIntegral bytesRead)
141− else return []
146+ else return BS.empty
147+ when (not $ BS.null stringRep) $
142− when (not $ null stringRep) $ logMsg $ "input bytes: " ++ show stringRep
148+ logMsg $ "input bytes: " ++ show (BS8.unpack stringRep)
143 return stringRep
149 return stringRep
144
150
145applyConfig :: Fd -> Config -> IO ()
151applyConfig :: Fd -> Config -> IO ()
@@ -150,30 +156,43 @@ applyConfig _ _ = fail "(vty) applyConfig was not provided a complete configurat
150parseEvent :: InputM Event
156parseEvent :: InputM Event
151parseEvent = do
157parseEvent = do
152 c <- use classifier
158 c <- use classifier
159+ s <- use classifierState
153 b <- use unprocessedBytes
160 b <- use unprocessedBytes
154− case c b of
161+ case c s b of
155 Valid e remaining -> do
162 Valid e remaining -> do
156 logMsg $ "valid parse: " ++ show e
163 logMsg $ "valid parse: " ++ show e
157 logMsg $ "remaining: " ++ show remaining
164 logMsg $ "remaining: " ++ show remaining
165+ classifierState .= ClassifierStart
158 unprocessedBytes .= remaining
166 unprocessedBytes .= remaining
159 return e
167 return e
160− _ -> mzero
168+ _ -> mzero
161
169
162dropInvalid :: InputM ()
170dropInvalid :: InputM ()
163dropInvalid = do
171dropInvalid = do
164 c <- use classifier
172 c <- use classifier
173+ s <- use classifierState
165 b <- use unprocessedBytes
174 b <- use unprocessedBytes
175+ case c s b of
176+ Chunk -> do
177+ classifierState .=
178+ case s of
179+ ClassifierStart -> ClassifierInChunk b []
180+ ClassifierInChunk p bs -> ClassifierInChunk p (b:bs)
181+ unprocessedBytes .= BS8.empty
166− when (c b == Invalid) $ do
182+ Invalid -> do
167− logMsg "dropping input bytes"
183+ logMsg "dropping input bytes"
184+ classifierState .= ClassifierStart
168− unprocessedBytes .= []
185+ unprocessedBytes .= BS8.empty
186+ _ -> return ()
169
187
170runInputProcessorLoop :: ClassifyMap -> Input -> IO ()
188runInputProcessorLoop :: ClassifyMap -> Input -> IO ()
171runInputProcessorLoop classifyTable input = do
189runInputProcessorLoop classifyTable input = do
172 let bufferSize = 1024
190 let bufferSize = 1024
173 allocaArray bufferSize $ \(bufferPtr :: Ptr Word8) -> do
191 allocaArray bufferSize $ \(bufferPtr :: Ptr Word8) -> do
192+ s0 <- InputState BS8.empty ClassifierStart
174− s0 <- InputState [] <$> readIORef (_configRef input)
193+ <$> readIORef (_configRef input)
175− <*> pure (InputBuffer bufferPtr bufferSize)
194+ <*> pure (InputBuffer bufferPtr bufferSize)
176− <*> pure (classify classifyTable)
195+ <*> pure (classify classifyTable)
177 runReaderT (evalStateT loopInputProcessor s0) input
196 runReaderT (evalStateT loopInputProcessor s0) input
178
197
179-- | Construct two IO actions: one to configure the terminal for Vty and
198-- | Construct two IO actions: one to configure the terminal for Vty and
src/Graphics/Vty/Input/Mouse.hs+19−17
@@ -15,10 +15,12 @@ import Graphics.Vty.Input.Classify.Types
15import Graphics.Vty.Input.Classify.Parse
15import Graphics.Vty.Input.Classify.Parse
16
16
17import Control.Monad.State
17import Control.Monad.State
18−import Data.List (isPrefixOf)
19import Data.Maybe (catMaybes)
18import Data.Maybe (catMaybes)
20import Data.Bits ((.&.))
19import Data.Bits ((.&.))
21
20
21+import qualified Data.ByteString.Char8 as BS8
22+import Data.ByteString.Char8 (ByteString)
23+
22-- A mouse event in SGR extended mode is
24-- A mouse event in SGR extended mode is
23--
25--
24-- '\ESC' '[' '<' B ';' X ';' Y ';' ('M'|'m')
26-- '\ESC' '[' '<' B ';' X ';' Y ';' ('M'|'m')
@@ -32,28 +34,28 @@ import Data.Bits ((.&.))
32
34
33-- | These sequences set xterm-based terminals to send mouse event
35-- | These sequences set xterm-based terminals to send mouse event
34-- sequences.
36-- sequences.
35−requestMouseEvents :: String
37+requestMouseEvents :: ByteString
36−requestMouseEvents = "\ESC[?1000h\ESC[?1002h\ESC[?1006h"
38+requestMouseEvents = BS8.pack "\ESC[?1000h\ESC[?1002h\ESC[?1006h"
37
39
38-- | These sequences disable mouse events.
40-- | These sequences disable mouse events.
39−disableMouseEvents :: String
41+disableMouseEvents :: ByteString
40−disableMouseEvents = "\ESC[?1000l\ESC[?1002l\ESC[?1006l"
42+disableMouseEvents = BS8.pack "\ESC[?1000l\ESC[?1002l\ESC[?1006l"
41
43
42-- | Does the specified string begin with a mouse event?
44-- | Does the specified string begin with a mouse event?
43−isMouseEvent :: String -> Bool
45+isMouseEvent :: ByteString -> Bool
44isMouseEvent s = isSGREvent s || isNormalEvent s
46isMouseEvent s = isSGREvent s || isNormalEvent s
45
47
46−isSGREvent :: String -> Bool
48+isSGREvent :: ByteString -> Bool
47−isSGREvent = isPrefixOf sgrPrefix
49+isSGREvent = BS8.isPrefixOf sgrPrefix
48
50
49−sgrPrefix :: String
51+sgrPrefix :: ByteString
50−sgrPrefix = "\ESC[M"
52+sgrPrefix = BS8.pack "\ESC[M"
51
53
52−isNormalEvent :: String -> Bool
54+isNormalEvent :: ByteString -> Bool
53−isNormalEvent = isPrefixOf normalPrefix
55+isNormalEvent = BS8.isPrefixOf normalPrefix
54
56
55−normalPrefix :: String
57+normalPrefix :: ByteString
56−normalPrefix = "\ESC[<"
58+normalPrefix = BS8.pack "\ESC[<"
57
59
58-- Modifier bits:
60-- Modifier bits:
59shiftBit :: Int
61shiftBit :: Int
@@ -87,8 +89,8 @@ scrollDown = 65
87hasBitSet :: Int -> Int -> Bool
89hasBitSet :: Int -> Int -> Bool
88hasBitSet val bit = val .&. bit > 0
90hasBitSet val bit = val .&. bit > 0
89
91
90−-- | Attempt to lassify an input string as a mouse event.
92+-- | Attempt to classify an input string as a mouse event.
91−classifyMouseEvent :: String -> KClass
93+classifyMouseEvent :: ByteString -> KClass
92classifyMouseEvent s = runParser s $ do
94classifyMouseEvent s = runParser s $ do
93 when (not $ isMouseEvent s) failParse
95 when (not $ isMouseEvent s) failParse
94
96
@@ -100,7 +102,7 @@ classifyMouseEvent s = runParser s $ do
100 'M' -> classifyNormalMouseEvent
102 'M' -> classifyNormalMouseEvent
101 _ -> failParse
103 _ -> failParse
102
104
103−-- Given a modifer/button value, determine which button was indicated
105+-- Given a modifier/button value, determine which button was indicated
104getSGRButton :: Int -> Parser Button
106getSGRButton :: Int -> Parser Button
105getSGRButton mods =
107getSGRButton mods =
106 let buttonMap = [ (leftButton, BLeft)
108 let buttonMap = [ (leftButton, BLeft)
src/Graphics/Vty/Input/Paste.hs+16−24
@@ -9,41 +9,33 @@ module Graphics.Vty.Input.Paste
9where
9where
10
10
11import qualified Data.ByteString.Char8 as BS8
11import qualified Data.ByteString.Char8 as BS8
12+import Data.ByteString.Char8 (ByteString)
12
13
13import Graphics.Vty.Input.Events
14import Graphics.Vty.Input.Events
14import Graphics.Vty.Input.Classify.Types
15import Graphics.Vty.Input.Classify.Types
15
16
16−import Data.List (isPrefixOf, isInfixOf)
17+bracketedPasteStart :: ByteString
18+bracketedPasteStart = BS8.pack "\ESC[200~"
17
19
18−bracketedPasteStart :: String
19−bracketedPasteStart = "\ESC[200~"
20−
21−bracketedPasteEnd :: String
20+bracketedPasteEnd :: ByteString
22−bracketedPasteEnd = "\ESC[201~"
21+bracketedPasteEnd = BS8.pack "\ESC[201~"
23
22
24-- | Does the input start a bracketed paste?
23-- | Does the input start a bracketed paste?
25−bracketedPasteStarted :: String -> Bool
24+bracketedPasteStarted :: ByteString -> Bool
26−bracketedPasteStarted = isPrefixOf bracketedPasteStart
25+bracketedPasteStarted = BS8.isPrefixOf bracketedPasteStart
27
26
28-- | Does the input contain a complete bracketed paste?
27-- | Does the input contain a complete bracketed paste?
29−bracketedPasteFinished :: String -> Bool
28+bracketedPasteFinished :: ByteString -> Bool
30−bracketedPasteFinished = isInfixOf bracketedPasteEnd
29+bracketedPasteFinished = BS8.isInfixOf bracketedPasteEnd
31
30
32-- | Parse a bracketed paste. This should only be called on a string if
31-- | Parse a bracketed paste. This should only be called on a string if
33-- both 'bracketedPasteStarted' and 'bracketedPasteFinished' return
32-- both 'bracketedPasteStarted' and 'bracketedPasteFinished' return
34-- 'True'.
33-- 'True'.
35−parseBracketedPaste :: String -> KClass
34+parseBracketedPaste :: ByteString -> KClass
36parseBracketedPaste s =
35parseBracketedPaste s =
37− let (p, rest) = takeUntil (drop (length bracketedPasteStart) s) bracketedPasteEnd
38− rest' = if bracketedPasteEnd `isPrefixOf` rest
39− then drop (length bracketedPasteEnd) rest
40− else rest
41− in Valid (EvPaste $ BS8.pack p) rest'
36+ Valid (EvPaste p) (BS8.drop endLen rest')
42−
37+ where
43−takeUntil :: (Eq a) => [a] -> [a] -> ([a],[a])
38+ startLen = BS8.length bracketedPasteStart
44−takeUntil [] _ = ([], [])
39+ endLen = BS8.length bracketedPasteEnd
45−takeUntil cs sub
40+ (_, rest ) = BS8.breakSubstring bracketedPasteStart s
46− | length cs < length sub = (cs, [])
41+ (p, rest') = BS8.breakSubstring bracketedPasteEnd . BS8.drop startLen $ rest
47− | take (length sub) cs == sub = ([], drop (length sub) cs)
48− | otherwise = let (pre, suf) = takeUntil (tail cs) sub
49− in (head cs:pre, suf)
src/Graphics/Vty/Input/Terminfo.hs+1−1
@@ -91,7 +91,7 @@ specialSupportKeys =
91 -- special support for ESC
91 -- special support for ESC
92 , ("\ESC",EvKey KEsc []), ("\ESC\ESC",EvKey KEsc [MMeta])
92 , ("\ESC",EvKey KEsc []), ("\ESC\ESC",EvKey KEsc [MMeta])
93 -- Special support for backspace
93 -- Special support for backspace
94− , ("\DEL",EvKey KBS []), ("\ESC\DEL",EvKey KBS [MMeta])
94+ , ("\DEL",EvKey KBS []), ("\ESC\DEL",EvKey KBS [MMeta]), ("\b",EvKey KBS [])
95 -- Special support for Enter
95 -- Special support for Enter
96 , ("\ESC\^J",EvKey KEnter [MMeta]), ("\^J",EvKey KEnter [])
96 , ("\ESC\^J",EvKey KEnter [MMeta]), ("\^J",EvKey KEnter [])
97 -- explicit support for tab
97 -- explicit support for tab
src/Graphics/Vty/Output.hs+5−4
@@ -58,11 +58,12 @@ import Data.Monoid ((<>))
58-- * If TERM contains "xterm" or "screen", use XTermColor.
58-- * If TERM contains "xterm" or "screen", use XTermColor.
59-- * otherwise use the TerminfoBased driver.
59-- * otherwise use the TerminfoBased driver.
60outputForConfig :: Config -> IO Output
60outputForConfig :: Config -> IO Output
61−outputForConfig Config{ outputFd = Just fd, termName = Just termName, .. } = do
61+outputForConfig Config{ outputFd = Just fd, termName = Just termName
62+ , colorMode = Just colorMode, .. } = do
62 t <- if "xterm" `isPrefixOf` termName || "screen" `isPrefixOf` termName
63 t <- if "xterm" `isPrefixOf` termName || "screen" `isPrefixOf` termName
63− then XTermColor.reserveTerminal termName fd
64+ then XTermColor.reserveTerminal termName fd colorMode
64 -- Not an xterm-like terminal. try for generic terminfo.
65 -- Not an xterm-like terminal. try for generic terminfo.
65− else TerminfoBased.reserveTerminal termName fd
66+ else TerminfoBased.reserveTerminal termName fd colorMode
66
67
67 case mouseMode of
68 case mouseMode of
68 Just s -> setMode t Mouse s
69 Just s -> setMode t Mouse s
@@ -77,7 +78,7 @@ outputForConfig config = (<> config) <$> standardIOConfig >>= outputForConfig
77
78
78-- | Sets the cursor position to the given output column and row.
79-- | Sets the cursor position to the given output column and row.
79--
80--
80−-- This is not necessarially the same as the character position with the
81+-- This is not necessarily the same as the character position with the
81-- same coordinates. Characters can be a variable number of columns in
82-- same coordinates. Characters can be a variable number of columns in
82-- width.
83-- width.
83--
84--
src/Graphics/Vty/Output/Interface.hs+23−17
@@ -3,6 +3,7 @@
3{-# LANGUAGE ExistentialQuantification #-}
3{-# LANGUAGE ExistentialQuantification #-}
4{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
5{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
6-- | This module provides an abstract interface for performing terminal
7-- | This module provides an abstract interface for performing terminal
7-- output. The only user-facing part of this API is 'Output'.
8-- output. The only user-facing part of this API is 'Output'.
8module Graphics.Vty.Output.Interface
9module Graphics.Vty.Output.Interface
@@ -78,9 +79,6 @@ data Output = Output
78 , displayBounds :: IO DisplayRegion
79 , displayBounds :: IO DisplayRegion
79 -- | Output the bytestring to the terminal device.
80 -- | Output the bytestring to the terminal device.
80 , outputByteBuffer :: BS.ByteString -> IO ()
81 , outputByteBuffer :: BS.ByteString -> IO ()
81− -- | Specifies the maximum number of colors supported by the
82− -- context.
83− , contextColorCount :: Int
84 -- | Specifies whether the cursor can be shown / hidden.
82 -- | Specifies whether the cursor can be shown / hidden.
85 , supportsCursorVisibility :: Bool
83 , supportsCursorVisibility :: Bool
86 -- | Indicates support for terminal modes for this output device.
84 -- | Indicates support for terminal modes for this output device.
@@ -116,6 +114,8 @@ data Output = Output
116 -- be a reliable indicator of whether the feature will work as
114 -- be a reliable indicator of whether the feature will work as
117 -- desired.
115 -- desired.
118 , supportsStrikethrough :: IO Bool
116 , supportsStrikethrough :: IO Bool
117+ -- | Returns how many colors the terminal supports.
118+ , outputColorMode :: ColorMode
119 }
119 }
120
120
121displayContext :: Output -> DisplayRegion -> IO DisplayContext
121displayContext :: Output -> DisplayRegion -> IO DisplayContext
@@ -309,17 +309,23 @@ limitAttrForDisplay t attr
309 where
309 where
310 clampColor Default = Default
310 clampColor Default = Default
311 clampColor KeepCurrent = KeepCurrent
311 clampColor KeepCurrent = KeepCurrent
312− clampColor (SetTo c) = clampColor' c
312+ clampColor (SetTo c) = clampColor' (outputColorMode t) c
313+
313− clampColor' (ISOColor v)
314+ clampColor' NoColor _ = Default
314− | contextColorCount t < 8 = Default
315+
316+ clampColor' ColorMode8 (ISOColor v)
315− | contextColorCount t < 16 && v >= 8 = SetTo $ ISOColor (v - 8)
317+ | v >= 8 = SetTo $ ISOColor (v - 8)
316− | otherwise = SetTo $ ISOColor v
318+ | otherwise = SetTo $ ISOColor v
317− clampColor' (Color240 v)
319+ clampColor' ColorMode8 _ = Default
318− -- Should we choose closest ISO color?
320+
319− | contextColorCount t < 8 = Default
321+ clampColor' ColorMode16 c@(ISOColor _) = SetTo c
320− | contextColorCount t < 16 = Default
322+ clampColor' ColorMode16 _ = Default
321− | contextColorCount t <= 256 = SetTo $ Color240 v
323+
324+ clampColor' (ColorMode240 _) c@(ISOColor _) = SetTo c
325+ clampColor' (ColorMode240 colorCount) c@(Color240 n)
326+ | n <= colorCount = SetTo c
322− | otherwise
327+ | otherwise = Default
323− = let p :: Double = fromIntegral v / 240.0
328+ clampColor' colorMode@(ColorMode240 _) (RGBColor r g b) =
324− v' = floor $ p * (fromIntegral $ contextColorCount t)
329+ clampColor' colorMode (color240 r g b)
325− in SetTo $ Color240 v'
330+
331+ clampColor' FullColor c = SetTo c
src/Graphics/Vty/Output/Mock.hs+3−2
@@ -11,6 +11,7 @@ module Graphics.Vty.Output.Mock
11where
11where
12
12
13import Graphics.Vty.Image (DisplayRegion)
13import Graphics.Vty.Image (DisplayRegion)
14+import Graphics.Vty.Attributes.Color (ColorMode(ColorMode16))
14import Graphics.Vty.Output.Interface
15import Graphics.Vty.Output.Interface
15
16
16import Blaze.ByteString.Builder.Word (writeWord8)
17import Blaze.ByteString.Builder.Word (writeWord8)
@@ -30,7 +31,7 @@ type MockData = IORef (UTF8.UTF8 BS.ByteString)
30-- without considering terminal specific issues.
31-- without considering terminal specific issues.
31--
32--
32-- The mock implementation is useful in manually determining if the
33-- The mock implementation is useful in manually determining if the
33−-- sequence of terminal operations matche the expected sequence. The
34+-- sequence of terminal operations matches the expected sequence. The
34-- requirement of the produced representation is simplicity in parsing
35-- requirement of the produced representation is simplicity in parsing
35-- the text representation and determining how the picture was mapped to
36-- the text representation and determining how the picture was mapped to
36-- terminal operations.
37-- terminal operations.
@@ -55,12 +56,12 @@ mockTerminal r = liftIO $ do
55 , outputByteBuffer = \bytes -> do
56 , outputByteBuffer = \bytes -> do
56 putStrLn $ "mock outputByteBuffer of " ++ show (BS.length bytes) ++ " bytes"
57 putStrLn $ "mock outputByteBuffer of " ++ show (BS.length bytes) ++ " bytes"
57 writeIORef outRef $ UTF8.fromRep bytes
58 writeIORef outRef $ UTF8.fromRep bytes
58− , contextColorCount = 16
59 , supportsCursorVisibility = True
59 , supportsCursorVisibility = True
60 , supportsMode = const False
60 , supportsMode = const False
61 , setMode = const $ const $ return ()
61 , setMode = const $ const $ return ()
62 , getModeStatus = const $ return False
62 , getModeStatus = const $ return False
63 , assumedStateRef = newAssumedStateRef
63 , assumedStateRef = newAssumedStateRef
64+ , outputColorMode = ColorMode16
64 , mkDisplayContext = \tActual rActual -> return $ DisplayContext
65 , mkDisplayContext = \tActual rActual -> return $ DisplayContext
65 { contextRegion = rActual
66 { contextRegion = rActual
66 , contextDevice = tActual
67 , contextDevice = tActual
src/Graphics/Vty/Output/TerminfoBased.hs+66−33
@@ -25,7 +25,7 @@ import Graphics.Vty.Image (DisplayRegion)
25import Graphics.Vty.DisplayAttributes
25import Graphics.Vty.DisplayAttributes
26import Graphics.Vty.Output.Interface
26import Graphics.Vty.Output.Interface
27
27
28−import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable)
28+import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable, writeWord8)
29
29
30import Data.IORef
30import Data.IORef
31import Data.Maybe (isJust, isNothing, fromJust)
31import Data.Maybe (isJust, isNothing, fromJust)
@@ -49,7 +49,6 @@ data TerminfoCaps = TerminfoCaps
49 , cup :: CapExpression
49 , cup :: CapExpression
50 , cnorm :: Maybe CapExpression
50 , cnorm :: Maybe CapExpression
51 , civis :: Maybe CapExpression
51 , civis :: Maybe CapExpression
52− , supportsNoColors :: Bool
53 , useAltColorMap :: Bool
52 , useAltColorMap :: Bool
54 , setForeColor :: CapExpression
53 , setForeColor :: CapExpression
55 , setBackColor :: CapExpression
54 , setBackColor :: CapExpression
@@ -104,28 +103,28 @@ sendCapToTerminal t cap capParams = do
104--
103--
105-- * Providing independent string capabilities for all display
104-- * Providing independent string capabilities for all display
106-- attributes.
105-- attributes.
107−reserveTerminal :: String -> Fd -> IO Output
106+reserveTerminal :: String -> Fd -> ColorMode -> IO Output
108−reserveTerminal termName outFd = do
107+reserveTerminal termName outFd colorMode = do
109 ti <- Terminfo.setupTerm termName
108 ti <- Terminfo.setupTerm termName
110 -- assumes set foreground always implies set background exists.
109 -- assumes set foreground always implies set background exists.
111 -- if set foreground is not set then all color changing style
110 -- if set foreground is not set then all color changing style
112 -- attributes are filtered.
111 -- attributes are filtered.
113 msetaf <- probeCap ti "setaf"
112 msetaf <- probeCap ti "setaf"
114 msetf <- probeCap ti "setf"
113 msetf <- probeCap ti "setf"
115− let (noColors, useAlt, setForeCap)
114+ let (useAlt, setForeCap)
116 = case msetaf of
115 = case msetaf of
117− Just setaf -> (False, False, setaf)
116+ Just setaf -> (False, setaf)
118 Nothing -> case msetf of
117 Nothing -> case msetf of
119− Just setf -> (False, True, setf)
118+ Just setf -> (True, setf)
120− Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
119+ Nothing -> (True, error $ "no fore color support for terminal " ++ termName)
121 msetab <- probeCap ti "setab"
120 msetab <- probeCap ti "setab"
122 msetb <- probeCap ti "setb"
121 msetb <- probeCap ti "setb"
123− let set_back_cap
122+ let setBackCap
124 = case msetab of
123 = case msetab of
124+ Just setab -> setab
125 Nothing -> case msetb of
125 Nothing -> case msetb of
126 Just setb -> setb
126 Just setb -> setb
127 Nothing -> error $ "no back color support for terminal " ++ termName
127 Nothing -> error $ "no back color support for terminal " ++ termName
128− Just setab -> setab
129
128
130 hyperlinkModeStatus <- newIORef False
129 hyperlinkModeStatus <- newIORef False
131 newAssumedStateRef <- newIORef initialAssumedState
130 newAssumedStateRef <- newIORef initialAssumedState
@@ -151,10 +150,9 @@ reserveTerminal termName outFd = do
151 <*> requireCap ti "cup"
150 <*> requireCap ti "cup"
152 <*> probeCap ti "cnorm"
151 <*> probeCap ti "cnorm"
153 <*> probeCap ti "civis"
152 <*> probeCap ti "civis"
154− <*> pure noColors
155 <*> pure useAlt
153 <*> pure useAlt
156 <*> pure setForeCap
154 <*> pure setForeCap
157− <*> pure set_back_cap
155+ <*> pure setBackCap
158 <*> requireCap ti "sgr0"
156 <*> requireCap ti "sgr0"
159 <*> requireCap ti "clear"
157 <*> requireCap ti "clear"
160 <*> requireCap ti "el"
158 <*> requireCap ti "el"
@@ -194,17 +192,12 @@ reserveTerminal termName outFd = do
194 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
192 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
195 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
193 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
196 ++ " Please report this bug to vty project."
194 ++ " Please report this bug to vty project."
197− , contextColorCount
198− = case supportsNoColors terminfoCaps of
199− False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
200− Nothing -> 8
201− Just v -> toEnum v
202− True -> 1
203 , supportsCursorVisibility = isJust $ civis terminfoCaps
195 , supportsCursorVisibility = isJust $ civis terminfoCaps
204 , supportsMode = terminfoModeSupported
196 , supportsMode = terminfoModeSupported
205 , setMode = terminfoSetMode
197 , setMode = terminfoSetMode
206 , getModeStatus = terminfoModeStatus
198 , getModeStatus = terminfoModeStatus
207 , assumedStateRef = newAssumedStateRef
199 , assumedStateRef = newAssumedStateRef
200+ , outputColorMode = colorMode
208 -- I think fix would help assure tActual is the only
201 -- I think fix would help assure tActual is the only
209 -- reference. I was having issues tho.
202 -- reference. I was having issues tho.
210 , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
203 , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
@@ -302,7 +295,7 @@ writeURLEscapes NoLinkChange =
302-- | Portably setting the display attributes is a giant pain in the ass.
295-- | Portably setting the display attributes is a giant pain in the ass.
303--
296--
304-- If the terminal supports the sgr capability (which sets the on/off
297-- If the terminal supports the sgr capability (which sets the on/off
305−-- state of each style directly ; and, for no good reason, resets the
298+-- state of each style directly; and, for no good reason, resets the
306-- colors to the default) this procedure is used:
299-- colors to the default) this procedure is used:
307--
300--
308-- 0. set the style attributes. This resets the fore and back color.
301-- 0. set the style attributes. This resets the fore and back color.
@@ -341,9 +334,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
341 -- The only way to reset either color, portably, to the default
334 -- The only way to reset either color, portably, to the default
342 -- is to use either the set state capability or the set default
335 -- is to use either the set state capability or the set default
343 -- capability.
336 -- capability.
344− True -> do
337+ True -> do
345 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
338 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
346− (fixedStyle attr )
339+ (fixedStyle attr)
347 (styleToApplySeq $ fixedStyle attr) of
340 (styleToApplySeq $ fixedStyle attr) of
348 -- only way to reset a color to the defaults
341 -- only way to reset a color to the defaults
349 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
342 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
@@ -376,9 +369,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
376 -- applied states.
369 -- applied states.
377 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
370 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
378 `mappend`
371 `mappend`
379− writeColorDiff setForeColor (foreColorDiff diffs)
372+ writeColorDiff Foreground (foreColorDiff diffs)
380 `mappend`
373 `mappend`
381− writeColorDiff setBackColor (backColorDiff diffs)
374+ writeColorDiff Background (backColorDiff diffs)
382 -- implicitly resets the colors to the defaults
375 -- implicitly resets the colors to the defaults
383 SetState state -> writeCapExpr (fromJust $ setAttrStates
376 SetState state -> writeCapExpr (fromJust $ setAttrStates
384 $ displayAttrCaps terminfoCaps
377 $ displayAttrCaps terminfoCaps
@@ -410,29 +403,65 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
410 | otherwise = mempty
403 | otherwise = mempty
411 setColors =
404 setColors =
412 (case fixedForeColor attr of
405 (case fixedForeColor attr of
413− Just c -> writeCapExpr (setForeColor terminfoCaps)
406+ Just c -> writeColor Foreground c
414− [toEnum $ colorMap c]
415 Nothing -> mempty)
407 Nothing -> mempty)
416 `mappend`
408 `mappend`
417 (case fixedBackColor attr of
409 (case fixedBackColor attr of
418− Just c -> writeCapExpr (setBackColor terminfoCaps)
410+ Just c -> writeColor Background c
419− [toEnum $ colorMap c]
420 Nothing -> mempty)
411 Nothing -> mempty)
421− writeColorDiff _f NoColorChange
412+ writeColorDiff _side NoColorChange
422 = mempty
413 = mempty
423− writeColorDiff _f ColorToDefault
414+ writeColorDiff _side ColorToDefault
424 = error "ColorToDefault is not a possible case for applyColorDiffs"
415 = error "ColorToDefault is not a possible case for applyColorDiffs"
425− writeColorDiff f (SetColor c)
416+ writeColorDiff side (SetColor c)
417+ = writeColor side c
418+
419+ writeColor side (RGBColor r g b) =
420+ case outputColorMode (contextDevice dc) of
421+ FullColor ->
422+ hardcodeColor side (r, g, b)
423+ _ ->
424+ error "clampColor should remove rgb colors in standard mode"
425+ writeColor side c =
426− = writeCapExpr (f terminfoCaps) [toEnum $ colorMap c]
426+ writeCapExpr (setSideColor side terminfoCaps) [toEnum $ colorMap c]
427+
428+-- a color can either be in the foreground or the background
429+data ColorSide = Foreground | Background
430+
431+-- get the capability for drawing a color on a specific side
432+setSideColor :: ColorSide -> TerminfoCaps -> CapExpression
433+setSideColor Foreground = setForeColor
434+setSideColor Background = setBackColor
435+
436+hardcodeColor :: ColorSide -> (Word8, Word8, Word8) -> Write
437+hardcodeColor side (r, g, b) =
438+ -- hardcoded color codes are formatted as "\x1b[{side};2;{r};{g};{b}m"
439+ mconcat [ writeStr "\x1b[", sideCode, delimiter, writeChar '2', delimiter
440+ , writeColor r, delimiter, writeColor g, delimiter, writeColor b
441+ , writeChar 'm']
442+ where
443+ writeChar = writeWord8 . fromIntegral . fromEnum
444+ writeStr = mconcat . map writeChar
445+ writeColor = writeStr . show
446+ delimiter = writeChar ';'
447+ -- 38/48 are used to set whether we should write to the
448+ -- foreground/background. I really don't want to know why.
449+ sideCode = case side of
450+ Foreground -> writeStr "38"
451+ Background -> writeStr "48"
427
452
428-- | The color table used by a terminal is a 16 color set followed by a
453-- | The color table used by a terminal is a 16 color set followed by a
429-- 240 color set that might not be supported by the terminal.
454-- 240 color set that might not be supported by the terminal.
430--
455--
431−-- This takes a Color which clearly identifies which pallete to use and
456+-- This takes a Color which clearly identifies which palette to use and
432−-- computes the index into the full 256 color pallete.
457+-- computes the index into the full 256 color palette.
433ansiColorIndex :: Color -> Int
458ansiColorIndex :: Color -> Int
434ansiColorIndex (ISOColor v) = fromEnum v
459ansiColorIndex (ISOColor v) = fromEnum v
435ansiColorIndex (Color240 v) = 16 + fromEnum v
460ansiColorIndex (Color240 v) = 16 + fromEnum v
461+ansiColorIndex (RGBColor _ _ _) =
462+ error $ unlines [ "Attempted to create color index from rgb color."
463+ , "This is currently unsupported, and shouldn't ever happen"
464+ ]
436
465
437-- | For terminals without setaf/setab
466-- | For terminals without setaf/setab
438--
467--
@@ -449,6 +478,10 @@ altColorIndex (ISOColor 6) = 3
449altColorIndex (ISOColor 7) = 7
478altColorIndex (ISOColor 7) = 7
450altColorIndex (ISOColor v) = fromEnum v
479altColorIndex (ISOColor v) = fromEnum v
451altColorIndex (Color240 v) = 16 + fromEnum v
480altColorIndex (Color240 v) = 16 + fromEnum v
481+altColorIndex (RGBColor _ _ _) =
482+ error $ unlines [ "Attempted to create color index from rgb color."
483+ , "This is currently unsupported, and shouldn't ever happen"
484+ ]
452
485
453{- | The sequence of terminfo caps to apply a given style are determined
486{- | The sequence of terminfo caps to apply a given style are determined
454 - according to these rules.
487 - according to these rules.
src/Graphics/Vty/Output/XTermColor.hs+23−12
@@ -10,18 +10,23 @@ where
10import Graphics.Vty.Output.Interface
10import Graphics.Vty.Output.Interface
11import Graphics.Vty.Input.Mouse
11import Graphics.Vty.Input.Mouse
12import Graphics.Vty.Input.Focus
12import Graphics.Vty.Input.Focus
13+import Graphics.Vty.Attributes.Color (ColorMode)
13import qualified Graphics.Vty.Output.TerminfoBased as TerminfoBased
14import qualified Graphics.Vty.Output.TerminfoBased as TerminfoBased
14
15
15import Blaze.ByteString.Builder (writeToByteString)
16import Blaze.ByteString.Builder (writeToByteString)
16import Blaze.ByteString.Builder.Word (writeWord8)
17import Blaze.ByteString.Builder.Word (writeWord8)
17
18
19+import qualified Data.ByteString.Char8 as BS8
20+import Data.ByteString.Char8 (ByteString)
21+import Foreign.Ptr (castPtr)
22+
18import Control.Monad (void, when)
23import Control.Monad (void, when)
19import Control.Monad.Trans
24import Control.Monad.Trans
20import Data.Char (toLower)
25import Data.Char (toLower)
21import Data.IORef
26import Data.IORef
22
27
23−import System.Posix.IO (fdWrite)
28+import System.Posix.IO (fdWriteBuf)
24−import System.Posix.Types (Fd)
29+import System.Posix.Types (ByteCount, Fd)
25import System.Posix.Env (getEnv)
30import System.Posix.Env (getEnv)
26
31
27import Data.List (isInfixOf)
32import Data.List (isInfixOf)
@@ -31,9 +36,15 @@ import Data.Maybe (catMaybes)
31import Data.Monoid ((<>))
36import Data.Monoid ((<>))
32#endif
37#endif
33
38
39+-- | Write a 'ByteString' to an 'Fd'.
40+fdWrite :: Fd -> ByteString -> IO ByteCount
41+fdWrite fd s =
42+ BS8.useAsCStringLen s $ \(buf,len) -> do
43+ fdWriteBuf fd (castPtr buf) (fromIntegral len)
44+
34-- | Construct an Xterm output driver. Initialize the display to UTF-8.
45-- | Construct an Xterm output driver. Initialize the display to UTF-8.
35−reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Fd -> m Output
46+reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Fd -> ColorMode -> m Output
36−reserveTerminal variant outFd = liftIO $ do
47+reserveTerminal variant outFd colorMode = liftIO $ do
37 let flushedPut = void . fdWrite outFd
48 let flushedPut = void . fdWrite outFd
38 -- If the terminal variant is xterm-color use xterm instead since,
49 -- If the terminal variant is xterm-color use xterm instead since,
39 -- more often than not, xterm-color is broken.
50 -- more often than not, xterm-color is broken.
@@ -41,7 +52,7 @@ reserveTerminal variant outFd = liftIO $ do
41
52
42 utf8a <- utf8Active
53 utf8a <- utf8Active
43 when (not utf8a) $ flushedPut setUtf8CharSet
54 when (not utf8a) $ flushedPut setUtf8CharSet
44− t <- TerminfoBased.reserveTerminal variant' outFd
55+ t <- TerminfoBased.reserveTerminal variant' outFd colorMode
45
56
46 mouseModeStatus <- newIORef False
57 mouseModeStatus <- newIORef False
47 focusModeStatus <- newIORef False
58 focusModeStatus <- newIORef False
@@ -100,19 +111,19 @@ utf8Active = do
100
111
101-- | Enable bracketed paste mode:
112-- | Enable bracketed paste mode:
102-- http://cirw.in/blog/bracketed-paste
113-- http://cirw.in/blog/bracketed-paste
103−enableBracketedPastes :: String
114+enableBracketedPastes :: ByteString
104−enableBracketedPastes = "\ESC[?2004h"
115+enableBracketedPastes = BS8.pack "\ESC[?2004h"
105
116
106-- | Disable bracketed paste mode:
117-- | Disable bracketed paste mode:
107−disableBracketedPastes :: String
118+disableBracketedPastes :: ByteString
108−disableBracketedPastes = "\ESC[?2004l"
119+disableBracketedPastes = BS8.pack "\ESC[?2004l"
109
120
110-- | These sequences set xterm based terminals to UTF-8 output.
121-- | These sequences set xterm based terminals to UTF-8 output.
111--
122--
112-- There is no known terminfo capability equivalent to this.
123-- There is no known terminfo capability equivalent to this.
113−setUtf8CharSet, setDefaultCharSet :: String
124+setUtf8CharSet, setDefaultCharSet :: ByteString
114−setUtf8CharSet = "\ESC%G"
125+setUtf8CharSet = BS8.pack "\ESC%G"
115−setDefaultCharSet = "\ESC%@"
126+setDefaultCharSet = BS8.pack "\ESC%@"
116
127
117xtermInlineHack :: Output -> IO ()
128xtermInlineHack :: Output -> IO ()
118xtermInlineHack t = do
129xtermInlineHack t = do
src/Graphics/Vty/Picture.hs+3−3
@@ -79,9 +79,6 @@ picForLayers is = Picture
79data Cursor =
79data Cursor =
80 -- | Hide the cursor
80 -- | Hide the cursor
81 NoCursor
81 NoCursor
82− -- | Show the cursor at the given logical column accounting for
83− -- character width in the presence of multi-column characters.
84− | PositionOnly !Bool !Int !Int
85 -- | Set the terminal's cursor position without displaying a cursor
82 -- | Set the terminal's cursor position without displaying a cursor
86 -- character. This is important for accessibility with screen
83 -- character. This is important for accessibility with screen
87 -- readers where a cursor position needs to be reported but we may
84 -- readers where a cursor position needs to be reported but we may
@@ -89,6 +86,9 @@ data Cursor =
89 -- reasons. The boolean argument indicates whether the positioning
86 -- reasons. The boolean argument indicates whether the positioning
90 -- should be absolute as with 'AbsoluteCursor' ('True') or logical
87 -- should be absolute as with 'AbsoluteCursor' ('True') or logical
91 -- as with 'Cursor' ('False').
88 -- as with 'Cursor' ('False').
89+ | PositionOnly !Bool !Int !Int
90+ -- | Show the cursor at the given logical column accounting for
91+ -- character width in the presence of multi-column characters.
92 | Cursor !Int !Int
92 | Cursor !Int !Int
93 -- | Show the cursor at the given absolute terminal column and row
93 -- | Show the cursor at the given absolute terminal column and row
94 | AbsoluteCursor !Int !Int
94 | AbsoluteCursor !Int !Int
src/Graphics/Vty/PictureToSpans.hs+1−1
@@ -72,7 +72,7 @@ displayOpsForPic pic r = Vector.create (combinedOpsForLayers pic r)
72-- | Returns the DisplayOps for an image rendered to a window the size
72-- | Returns the DisplayOps for an image rendered to a window the size
73-- of the image.
73-- of the image.
74--
74--
75−-- largerly used only for debugging.
75+-- largely used only for debugging.
76displayOpsForImage :: Image -> DisplayOps
76displayOpsForImage :: Image -> DisplayOps
77displayOpsForImage i = displayOpsForPic (picForImage i) (imageWidth i, imageHeight i)
77displayOpsForImage i = displayOpsForPic (picForImage i) (imageWidth i, imageHeight i)
78
78
test/VerifyAttributes.hsdeleted−30
@@ -1,30 +0,0 @@
1−module VerifyAttributes where
2−
3−import Verify
4−
5−import Data.Semigroup((<>))
6−
7−import Graphics.Vty.Attributes(MaybeDefault(Default, KeepCurrent, SetTo))
8−
9−instance Arbitrary a => Arbitrary (MaybeDefault a) where
10− arbitrary = oneof [pure Default, pure KeepCurrent, SetTo <$> arbitrary]
11−
12−oldSem :: MaybeDefault a -> MaybeDefault a -> MaybeDefault a
13−oldSem Default Default = Default
14−oldSem Default KeepCurrent = Default
15−oldSem Default (SetTo v) = SetTo v
16−oldSem KeepCurrent Default = Default
17−oldSem KeepCurrent KeepCurrent = KeepCurrent
18−oldSem KeepCurrent (SetTo v) = SetTo v
19−oldSem (SetTo _v) Default = Default
20−oldSem (SetTo v) KeepCurrent = SetTo v
21−oldSem (SetTo _) (SetTo v) = SetTo v
22−
23−sameSemigroupValue :: MaybeDefault Int -> MaybeDefault Int -> Bool
24−sameSemigroupValue xa xb = xa <> xb == oldSem xa xb
25−
26−tests :: IO [Test]
27−tests = return
28− [ verify "check that the new Semigroup of MaybeDefault is equivalent to the old one" sameSemigroupValue
29− ]
30−
test/VerifyEmptyImageProps.hs+1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
1module VerifyEmptyImageProps where
2module VerifyEmptyImageProps where
2
3
3import Verify
4import Verify
test/VerifyEvalTerminfoCaps.hs+1
@@ -1,5 +1,6 @@
1{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE NamedFieldPuns #-}
2{-# LANGUAGE NamedFieldPuns #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
3module VerifyEvalTerminfoCaps where
4module VerifyEvalTerminfoCaps where
4
5
5import Blaze.ByteString.Builder.Internal.Write (runWrite, getBound)
6import Blaze.ByteString.Builder.Internal.Write (runWrite, getBound)
test/VerifyImageOps.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
1module VerifyImageOps where
2module VerifyImageOps where
2
3
3import Graphics.Vty.Attributes
4import Graphics.Vty.Attributes
@@ -136,7 +137,7 @@ cropBottomLimitsHeight :: Image -> Int -> Property
136cropBottomLimitsHeight i v = v >= 0 ==>
137cropBottomLimitsHeight i v = v >= 0 ==>
137 v >= imageHeight (cropBottom v i)
138 v >= imageHeight (cropBottom v i)
138
139
139−-- rediculous tests just to satisfy my desire for nice code coverage :-P
140+-- ridiculous tests just to satisfy my desire for nice code coverage :-P
140canShowImage :: Image -> Bool
141canShowImage :: Image -> Bool
141canShowImage i = length (show i) > 0
142canShowImage i = length (show i) > 0
142
143
test/VerifyOutput.hs+7−2
@@ -1,6 +1,7 @@
1−-- We setup the environment to envoke certain terminals of interest.
1+-- We setup the environment to invoke certain terminals of interest.
2-- This assumes appropriate definitions exist in the current environment
2-- This assumes appropriate definitions exist in the current environment
3-- for the terminals of interest.
3-- for the terminals of interest.
4+{-# LANGUAGE ScopedTypeVariables #-}
4module VerifyOutput where
5module VerifyOutput where
5
6
6import Verify
7import Verify
@@ -34,7 +35,11 @@ smokeTestTermNonMac termName i = liftIOResult $ do
34smokeTestTerm :: String -> Image -> IO Result
35smokeTestTerm :: String -> Image -> IO Result
35smokeTestTerm termName i = do
36smokeTestTerm termName i = do
36 nullOut <- openFd "/dev/null" WriteOnly Nothing defaultFileFlags
37 nullOut <- openFd "/dev/null" WriteOnly Nothing defaultFileFlags
37− t <- outputForConfig $ defaultConfig { outputFd = Just nullOut, termName = Just termName }
38+ t <- outputForConfig $ defaultConfig
39+ { outputFd = Just nullOut
40+ , termName = Just termName
41+ , colorMode = Just NoColor
42+ }
38 -- putStrLn $ "context color count: " ++ show (contextColorCount t)
43 -- putStrLn $ "context color count: " ++ show (contextColorCount t)
39 reserveDisplay t
44 reserveDisplay t
40 dc <- displayContext t (100,100)
45 dc <- displayContext t (100,100)
test/VerifyParseTerminfoCaps.hs+1
@@ -1,4 +1,5 @@
1{-# LANGUAGE NamedFieldPuns #-}
1{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
2module VerifyParseTerminfoCaps where
3module VerifyParseTerminfoCaps where
3
4
4import Prelude hiding ( catch )
5import Prelude hiding ( catch )
test/VerifyUsingMockInput.hs+4−1
@@ -1,5 +1,6 @@
1{-# LANGUAGE MultiParamTypeClasses #-}
1{-# LANGUAGE MultiParamTypeClasses #-}
2{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
3-- Generate some input bytes and delays between blocks of input bytes.
4-- Generate some input bytes and delays between blocks of input bytes.
4-- Verify the events produced are as expected.
5-- Verify the events produced are as expected.
5module Main where
6module Main where
@@ -131,7 +132,9 @@ assertEventsFromSynInput table inputSpec expectedEvents = do
131 readLoop 0 = return ()
132 readLoop 0 = return ()
132 readLoop n = do
133 readLoop n = do
133 e <- atomically $ readTChan $ input^.eventChannel
134 e <- atomically $ readTChan $ input^.eventChannel
135+ case e of
134− modifyIORef eventsRef ((:) e)
136+ InputEvent ev -> modifyIORef eventsRef ((:) ev)
137+ ResumeAfterSignal -> return ()
135 readLoop (n - 1)
138 readLoop (n - 1)
136 genEventsUsingIoActions maxDuration writeWaitClose readEvents
139 genEventsUsingIoActions maxDuration writeWaitClose readEvents
137 outEvents <- reverse <$> readIORef eventsRef
140 outEvents <- reverse <$> readIORef eventsRef
test/interactive_terminal_test.hs+1−1
@@ -364,7 +364,7 @@ Did the test output match the description?
364|]
364|]
365 defaultSuccessConfirmResults
365 defaultSuccessConfirmResults
366
366
367−-- Explicitely definethe bytes that encode each example text.
367+-- Explicitly define the bytes that encode each example text.
368-- This avoids any issues with how the compiler represents string literals.
368-- This avoids any issues with how the compiler represents string literals.
369--
369--
370-- This document is UTF-8 encoded so the UTF-8 string is still included for
370-- This document is UTF-8 encoded so the UTF-8 string is still included for
vty.cabal+3−48
@@ -1,5 +1,5 @@
1name: vty
1name: vty
2−version: 5.33
2+version: 5.35.1
3license: BSD3
3license: BSD3
4license-file: LICENSE
4license-file: LICENSE
5author: AUTHORS
5author: AUTHORS
@@ -117,8 +117,6 @@ library
117
117
118 hs-source-dirs: src
118 hs-source-dirs: src
119
119
120− default-extensions: ScopedTypeVariables
121−
122 ghc-options: -O2 -funbox-strict-fields -Wall -fspec-constr -fspec-constr-count=10
120 ghc-options: -O2 -funbox-strict-fields -Wall -fspec-constr -fspec-constr-count=10
123
121
124 ghc-prof-options: -O2 -funbox-strict-fields -caf-all -Wall -fspec-constr -fspec-constr-count=10
122 ghc-prof-options: -O2 -funbox-strict-fields -caf-all -Wall -fspec-constr -fspec-constr-count=10
@@ -143,7 +141,6 @@ executable vty-mode-demo
143 hs-source-dirs: demos
141 hs-source-dirs: demos
144
142
145 default-language: Haskell2010
143 default-language: Haskell2010
146− default-extensions: ScopedTypeVariables
147 ghc-options: -threaded
144 ghc-options: -threaded
148
145
149 build-depends: vty,
146 build-depends: vty,
@@ -158,7 +155,6 @@ executable vty-demo
158 hs-source-dirs: demos
155 hs-source-dirs: demos
159
156
160 default-language: Haskell2010
157 default-language: Haskell2010
161− default-extensions: ScopedTypeVariables
162 ghc-options: -threaded
158 ghc-options: -threaded
163
159
164 build-depends: vty,
160 build-depends: vty,
@@ -170,7 +166,6 @@ executable vty-demo
170
166
171test-suite verify-using-mock-terminal
167test-suite verify-using-mock-terminal
172 default-language: Haskell2010
168 default-language: Haskell2010
173− default-extensions: ScopedTypeVariables
174
169
175 type: detailed-0.9
170 type: detailed-0.9
176
171
@@ -203,7 +198,6 @@ test-suite verify-using-mock-terminal
203
198
204test-suite verify-terminal
199test-suite verify-terminal
205 default-language: Haskell2010
200 default-language: Haskell2010
206− default-extensions: ScopedTypeVariables
207
201
208 type: detailed-0.9
202 type: detailed-0.9
209
203
@@ -236,7 +230,6 @@ test-suite verify-terminal
236
230
237test-suite verify-display-attributes
231test-suite verify-display-attributes
238 default-language: Haskell2010
232 default-language: Haskell2010
239− default-extensions: ScopedTypeVariables
240
233
241 type: detailed-0.9
234 type: detailed-0.9
242
235
@@ -268,7 +261,6 @@ test-suite verify-display-attributes
268
261
269test-suite verify-empty-image-props
262test-suite verify-empty-image-props
270 default-language: Haskell2010
263 default-language: Haskell2010
271− default-extensions: ScopedTypeVariables
272
264
273 type: detailed-0.9
265 type: detailed-0.9
274
266
@@ -294,7 +286,6 @@ test-suite verify-empty-image-props
294
286
295test-suite verify-eval-terminfo-caps
287test-suite verify-eval-terminfo-caps
296 default-language: Haskell2010
288 default-language: Haskell2010
297− default-extensions: ScopedTypeVariables
298
289
299 type: detailed-0.9
290 type: detailed-0.9
300
291
@@ -323,7 +314,6 @@ test-suite verify-eval-terminfo-caps
323
314
324test-suite verify-image-ops
315test-suite verify-image-ops
325 default-language: Haskell2010
316 default-language: Haskell2010
326− default-extensions: ScopedTypeVariables
327
317
328 type: detailed-0.9
318 type: detailed-0.9
329
319
@@ -351,7 +341,6 @@ test-suite verify-image-ops
351
341
352test-suite verify-image-trans
342test-suite verify-image-trans
353 default-language: Haskell2010
343 default-language: Haskell2010
354− default-extensions: ScopedTypeVariables
355
344
356 type: detailed-0.9
345 type: detailed-0.9
357
346
@@ -379,7 +368,6 @@ test-suite verify-image-trans
379
368
380test-suite verify-inline
369test-suite verify-inline
381 default-language: Haskell2010
370 default-language: Haskell2010
382− default-extensions: ScopedTypeVariables
383
371
384 type: detailed-0.9
372 type: detailed-0.9
385
373
@@ -406,7 +394,6 @@ test-suite verify-inline
406
394
407test-suite verify-parse-terminfo-caps
395test-suite verify-parse-terminfo-caps
408 default-language: Haskell2010
396 default-language: Haskell2010
409− default-extensions: ScopedTypeVariables
410
397
411 type: detailed-0.9
398 type: detailed-0.9
412
399
@@ -435,7 +422,6 @@ test-suite verify-parse-terminfo-caps
435
422
436test-suite verify-simple-span-generation
423test-suite verify-simple-span-generation
437 default-language: Haskell2010
424 default-language: Haskell2010
438− default-extensions: ScopedTypeVariables
439
425
440 type: detailed-0.9
426 type: detailed-0.9
441
427
@@ -467,7 +453,6 @@ test-suite verify-simple-span-generation
467
453
468test-suite verify-crop-span-generation
454test-suite verify-crop-span-generation
469 default-language: Haskell2010
455 default-language: Haskell2010
470− default-extensions: ScopedTypeVariables
471
456
472 type: detailed-0.9
457 type: detailed-0.9
473
458
@@ -499,7 +484,6 @@ test-suite verify-crop-span-generation
499
484
500test-suite verify-layers-span-generation
485test-suite verify-layers-span-generation
501 default-language: Haskell2010
486 default-language: Haskell2010
502− default-extensions: ScopedTypeVariables
503
487
504 type: detailed-0.9
488 type: detailed-0.9
505
489
@@ -530,7 +514,6 @@ test-suite verify-layers-span-generation
530
514
531test-suite verify-color-mapping
515test-suite verify-color-mapping
532 default-language: Haskell2010
516 default-language: Haskell2010
533− default-extensions: ScopedTypeVariables
534
517
535 type: detailed-0.9
518 type: detailed-0.9
536
519
@@ -554,36 +537,8 @@ test-suite verify-color-mapping
554 utf8-string >= 0.3 && < 1.1,
537 utf8-string >= 0.3 && < 1.1,
555 vector >= 0.7
538 vector >= 0.7
556
539
557−test-suite verify-semigroup-maybedefault
558− default-language: Haskell2010
559− default-extensions: ScopedTypeVariables
560−
561− type: detailed-0.9
562−
563− hs-source-dirs: test
564−
565− test-module: VerifyAttributes
566−
567− other-modules: Verify
568−
569− build-depends: vty,
570− Cabal >= 1.20,
571− QuickCheck >= 2.7,
572− random >= 1.0 && < 1.3,
573− base >= 4.8 && < 5,
574− bytestring,
575− containers,
576− deepseq >= 1.1 && < 1.5,
577− mtl >= 1.1.1.0 && < 2.3,
578− text >= 0.11.3,
579− unix,
580− utf8-string >= 0.3 && < 1.1,
581− vector >= 0.7
582−
583−
584test-suite verify-utf8-width
540test-suite verify-utf8-width
585 default-language: Haskell2010
541 default-language: Haskell2010
586− default-extensions: ScopedTypeVariables
587
542
588 type: detailed-0.9
543 type: detailed-0.9
589
544
@@ -609,7 +564,6 @@ test-suite verify-utf8-width
609
564
610test-suite verify-using-mock-input
565test-suite verify-using-mock-input
611 default-language: Haskell2010
566 default-language: Haskell2010
612− default-extensions: ScopedTypeVariables
613
567
614 type: exitcode-stdio-1.0
568 type: exitcode-stdio-1.0
615
569
@@ -617,6 +571,8 @@ test-suite verify-using-mock-input
617
571
618 main-is: VerifyUsingMockInput.hs
572 main-is: VerifyUsingMockInput.hs
619
573
574+ other-modules: Verify.Graphics.Vty.Output
575+
620 build-depends: vty,
576 build-depends: vty,
621 Cabal >= 1.20,
577 Cabal >= 1.20,
622 QuickCheck >= 2.7,
578 QuickCheck >= 2.7,
@@ -643,7 +599,6 @@ test-suite verify-using-mock-input
643
599
644test-suite verify-config
600test-suite verify-config
645 default-language: Haskell2010
601 default-language: Haskell2010
646− default-extensions: ScopedTypeVariables
647
602
648 type: exitcode-stdio-1.0
603 type: exitcode-stdio-1.0
649
604