vty-examples (empty) → 5.0.0
raw patch · 6 files changed
+1544/−0 lines, 6 filesdep +Cabaldep +QuickCheckdep +arraysetup-changed
Dependencies added: Cabal, QuickCheck, array, base, bytestring, containers, data-default, deepseq, lens, mtl, parallel, parsec, random, string-qq, terminfo, text, unix, utf8-string, vector, vty
Files
- EventEcho.hs +41/−0
- Rouge.hs +147/−0
- Setup.hs +2/−0
- benchmark.hs +56/−0
- interactive_terminal_test.hs +1184/−0
- vty-examples.cabal +114/−0
+ EventEcho.hs view
@@ -0,0 +1,41 @@+module Main where++import Graphics.Vty++import Control.Applicative+import Control.Arrow+import Control.Monad.RWS++import Data.Default (def)+import Data.Sequence (Seq, (<|) )+import qualified Data.Sequence as Seq+import Data.Foldable++eventBufferSize = 1000++type App = RWST Vty () (Seq String) IO++main = do+ vty <- mkVty def+ _ <- execRWST (vtyInteract False) vty Seq.empty+ shutdown vty++vtyInteract :: Bool -> App ()+vtyInteract shouldExit = do+ updateDisplay+ unless shouldExit $ handleNextEvent >>= vtyInteract++updateDisplay :: App ()+updateDisplay = do+ let info = string defAttr "Press ESC to exit."+ eventLog <- foldMap (string defAttr) <$> get+ let pic = picForImage $ info <-> eventLog+ vty <- ask+ liftIO $ update vty pic++handleNextEvent = ask >>= liftIO . nextEvent >>= handleEvent+ where+ handleEvent e = do+ modify $ (<|) (show e) >>> Seq.take eventBufferSize+ return $ e == EvKey KEsc []+
+ Rouge.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE TemplateHaskell #-}+module Main where++import Graphics.Vty++import Data.Array+import qualified Data.ByteString as B+import Data.Default (def)+import Data.Word++import Control.Applicative+import Control.Lens hiding (Level)+import Control.Monad+import Control.Monad.RWS+import Control.Monad.Writer++import System.IO+import System.Random++data Dude = Dude+ { dudeX :: Int+ , dudeY :: Int+ } deriving (Show,Eq)++data World = World+ { dude :: Dude+ , level :: Level+ }+ deriving (Show,Eq)++data Level = Level+ { start :: (Int, Int)+ , end :: (Int, Int)+ , geo :: Array (Int, Int) LevelPiece+ -- building the geo image is expensive. Cache it. Though VTY should go through greater lengths+ -- to avoid the need to cache images.+ , geoImage :: Image+ }+ deriving (Show,Eq)++data LevelPiece+ = EmptySpace+ | Rock+ deriving (Show, Eq)++type Game = RWST Vty () World IO++main = do + vty <- mkVty def+ level0 <- mkLevel 1+ let world0 = World (Dude (fst $ start level0) (snd $ start level0)) level0+ (_finalWorld, ()) <- execRWST (play >> updateDisplay) vty world0+ shutdown vty++mkLevel difficulty = do+ let size = 80 * difficulty+ [levelWidth, levelHeight] <- replicateM 2 $ randomRIO (size,size)+ let randomP = (,) <$> randomRIO (2, levelWidth-3) <*> randomRIO (2, levelHeight-3)+ start <- randomP+ end <- randomP+ -- first the base geography: all rocks+ let baseGeo = array ((0,0), (levelWidth, levelHeight))+ [((x,y),Rock) | x <- [0..levelWidth-1], y <- [0..levelHeight-1]]+ -- next the empty spaces that make the rooms+ -- for this we generate a number of center points+ centers <- replicateM (2 ^ difficulty + difficulty) randomP+ -- generate rooms for all those points, plus the start and end+ geo <- foldM (addRoom levelWidth levelHeight) baseGeo (start : end : centers)+ return $ Level start end geo (buildGeoImage geo)++addRoom levelWidth levelHeight geo (centerX, centerY) = do+ size <- randomRIO (5,15)+ let xMin = max 1 (centerX - size)+ xMax = min (levelWidth - 1) (centerX + size)+ yMin = max 1 (centerY - size)+ yMax = min (levelHeight - 1) (centerY + size)+ let room = [((x,y), EmptySpace) | x <- [xMin..xMax - 1], y <- [yMin..yMax - 1]]+ return (geo // room)++imageForGeo EmptySpace = char (defAttr `withBackColor` green) ' '+imageForGeo Rock = char defAttr 'X'++pieceA = defAttr `withForeColor` blue `withBackColor` green+dumpA = defAttr `withStyle` reverseVideo++play = do+ updateDisplay+ done <- processEvent+ unless done play++processEvent = do+ k <- ask >>= liftIO . nextEvent+ if k == EvKey KEsc []+ then return True+ else do+ case k of+ EvKey (KChar 'r') [MCtrl] -> ask >>= liftIO . refresh+ EvKey KLeft [] -> moveDude (-1) 0+ EvKey KRight [] -> moveDude 1 0+ EvKey KUp [] -> moveDude 0 (-1)+ EvKey KDown [] -> moveDude 0 1+ _ -> return ()+ return False++moveDude dx dy = do+ vty <- ask+ world <- get+ let Dude x y = dude world+ let x' = x + dx+ y' = y + dy+ -- this is only valid because the level generation assures the border is always Rock+ case geo (level world) ! (x',y') of+ EmptySpace -> put $ world { dude = Dude x' y' }+ _ -> return ()++updateDisplay :: Game ()+updateDisplay = do+ let info = string defAttr "Move with the arrows keys. Press ESC to exit."+ -- determine offsets to place the dude in the center of the level.+ (w,h) <- asks outputIface >>= liftIO . displayBounds+ theDude <- gets dude+ let ox = (w `div` 2) - dudeX theDude+ oy = (h `div` 2) - dudeY theDude+ -- translate the world images to place the dude in the center of the level.+ world' <- map (translate ox oy) <$> world+ let pic = picForLayers $ info : world'+ vty <- ask+ liftIO $ update vty pic++world :: Game [Image]+world = do+ theDude <- gets dude+ theLevel <- gets level+ let dudeImage = translate (dudeX theDude) (dudeY theDude) (char pieceA '@')+ return [dudeImage, geoImage theLevel]++buildGeoImage geo =+ let (geoWidth, geoHeight) = snd $ bounds geo+ -- seems like a the repeated index operation should be removable. This is not performing random+ -- access but (presumably) access in order of index.+ in vertCat [ geoRow+ | y <- [0..geoHeight-1]+ , let geoRow = horizCat [ i+ | x <- [0..geoWidth-1]+ , let i = imageForGeo (geo ! (x,y))+ ]+ ]
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchmark.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE QuasiQuotes #-}+module Main where++import Graphics.Vty++import qualified BenchImageFuzz+import qualified BenchNoDiffOpt+import qualified BenchRenderChar+import qualified BenchVerticalScroll++import Control.Monad++import Data.Maybe+import Data.List++import System.Environment+import System.Posix.Process++import Verify++main = do+ args <- getArgs+ let benches = [ ("no-diff-opt-0", BenchNoDiffOpt.bench0)+ , ("render-char-0", BenchRenderChar.bench0)+ , ("render-char-1", BenchRenderChar.bench1)+ , ("vertical-scroll-0", BenchVerticalScroll.bench0)+ , ("image-fuzz-0", BenchImageFuzz.bench0) ]+ help = forM_ benches $ \(b,_) -> putStrLn $ "--" ++ b+ case args of+ ["--help"] -> help+ ["-h" ] -> help+ _ -> do+ let args' = if args /= []+ then map (drop 2) args+ else map fst benches+ -- drop the dash-dash "--"+ results <- forM args' $ \bName -> do+ case lookup bName benches of+ Just b -> bench bName b+ Nothing -> fail $ "No benchmark named " ++ bName+ print results+ return ()++bench bName b = do+ putStrLn $ "starting " ++ bName+ Bench bDataGen bProc <- b+ bData <- bDataGen+ startTimes <- bData `deepseq` getProcessTimes+ bProc bData+ endTimes <- getProcessTimes+ let ut = userTime endTimes - userTime startTimes+ st = systemTime endTimes - systemTime startTimes+ putStrLn $ "user time: " ++ show ut+ putStrLn $ "system time: " ++ show st+ return (bName, ut, st)+
+ interactive_terminal_test.hs view
@@ -0,0 +1,1184 @@+{-# LANGUAGE QuasiQuotes #-}+module Main where++import Graphics.Vty+import Graphics.Vty.Attributes+import Graphics.Vty.Inline+import Graphics.Vty.Picture+import Graphics.Vty.Output++import Control.Concurrent (threadDelay)+import Control.Exception+import Control.Monad++import Data.Default (def)+import Data.List ( lookup )+import Data.Maybe ( isJust, fromJust )+import Data.Monoid+import Data.String.QQ+import Data.Word++import Foreign.Marshal.Array ++import qualified System.Environment as Env++import System.IO ( hFlush, hPutStr, hPutBuf, stdout )++main = do+ printIntro++outputFilePath = "test_results.list"++printIntro = do+ putStr $ [s| +This is an interactive verification program for the terminal input and output+support of the VTY library. This will ask a series of questions about what you+see on screen. The goal is to verify that VTY's output and input support+performs as expected with your terminal.++This program produces a file named + |] ++ outputFilePath ++ [s| +in the current directory that contains the results for each test assertion. This+can be emailed to coreyoconnor@gmail.com and used by the VTY authors to improve+support for your terminal. No personal information is contained in the report.++Each test follows, more or less, the following format:+ 0. A description of the test is printed which will include a detailed+ description of what VTY is going to try and what the expected results are.+ Press return to move on.+ 1. The program will produce some output or ask for you to press a key.+ 2. You will then be asked to confirm if the behavior matched the provided+ description. Just pressing enter implies the default response that+ everything was as expected. ++All the tests assume the following about the terminal display:+ 0. The terminal display will not be resized during a test and is at least 80 + characters in width. + 1. The terminal display is using a monospaced font for both single width and+ double width characters.+ 2. A double width character is displayed with exactly twice the width of a + single column character. This may require adjusting the font used by the+ terminal. At least, that is the case using xterm. + 3. Fonts are installed, and usable by the terminal, that define glyphs for+ a good range of the unicode characters. Each test involving unicode display+ describes the expected appearance of each glyph. ++Thanks for the help! :-D+To exit the test early enter "q" anytime at the following menu screen.++If any test fails then please post an issue to+ https://github.com/coreyoconnor/vty/issues+with the test_results.list file pasted into the issue. A suitable summary is:+"interactive terminal test failure".+|]+ waitForReturn+ results <- doTestMenu 1+ envAttributes <- mapM ( \envName -> Control.Exception.catch ( Env.getEnv envName >>= return . (,) envName ) + ( \ (_ :: SomeException) -> return (envName, "") ) + ) + [ "TERM", "COLORTERM", "LANG", "TERM_PROGRAM", "XTERM_VERSION" ]+ t <- outputForCurrentTerminal def+ let resultsTxt = show envAttributes ++ "\n" + ++ terminalID t ++ "\n"+ ++ show results ++ "\n"+ releaseTerminal t+ writeFile outputFilePath resultsTxt++waitForReturn = do+ putStr "\n(press return to continue)"+ hFlush stdout+ getLine++testMenu :: [(String, Test)]+testMenu = zip (map show [1..]) allTests++doTestMenu :: Int -> IO [(String, Bool)]+doTestMenu nextID + | nextID > length allTests = do+ putStrLn $ "Done! Please email the " ++ outputFilePath ++ " file to coreyoconnor@gmail.com"+ return []+ | otherwise = do+ displayTestMenu+ putStrLn $ "Press return to start with #" ++ show nextID ++ "."+ putStrLn "Enter a test number to perform only that test."+ putStrLn "q (or control-C) to quit."+ putStr "> "+ hFlush stdout+ s <- getLine >>= return . filter (/= '\n')+ case s of+ "q" -> return mempty+ "" -> do + r <- runTest $ show nextID + rs <- doTestMenu ( nextID + 1 )+ return $ r : rs+ i | isJust ( lookup i testMenu ) -> do+ r <- runTest i + rs <- doTestMenu ( read i + 1 )+ return $ r : rs+ where+ displayTestMenu + = mapM_ displayTestMenu' testMenu+ displayTestMenu' ( i, t ) + = putStrLn $ ( if i == show nextID + then "> " + else " "+ ) ++ i ++ ". " ++ testName t++runTest :: String -> IO (String, Bool)+runTest i = do+ let t = fromJust $ lookup i testMenu + printSummary t+ waitForReturn+ testAction t+ r <- confirmResults t+ return (testID t, r)++defaultSuccessConfirmResults = do+ putStr "\n"+ putStr "[Y/n] "+ hFlush stdout+ r <- getLine+ case r of+ "" -> return True+ "y" -> return True+ "Y" -> return True+ "n" -> return False++data Test = Test+ { testName :: String+ , testID :: String+ , testAction :: IO ()+ , printSummary :: IO ()+ , confirmResults :: IO Bool+ }++allTests + = [ reserveOutputTest + , displayBoundsTest0+ , displayBoundsTest1+ , displayBoundsTest2+ , displayBoundsTest3+ , unicodeSingleWidth0+ , unicodeSingleWidth1+ , unicodeDoubleWidth0+ , unicodeDoubleWidth1+ , attributesTest0+ , attributesTest1+ , attributesTest2+ , attributesTest3+ , attributesTest4+ , attributesTest5+ , inlineTest0+ , inlineTest1+ , inlineTest2+ , cursorHideTest0+ , vertCropTest0+ , vertCropTest1+ , vertCropTest2+ , vertCropTest3+ , horizCropTest0+ , horizCropTest1+ , horizCropTest2+ , horizCropTest3+ , layer0+ , layer1+ ]++reserveOutputTest = Test + { testName = "Initialize and reserve terminal output then restore previous state."+ , testID = "reserveOutputTest"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ putStrLn "Line 1"+ putStrLn "Line 2"+ putStrLn "Line 3"+ putStrLn "Line 4 (press return)"+ hFlush stdout+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared. + 1. Four lines of text should be visible.+ 1. The cursor should be visible and at the start of the fifth line.++After return is pressed for the second time this test then:+ * The screen containing the test summary should be restored;+ * The cursor is visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++displayBoundsTest0 = Test+ { testName = "Verify display bounds are correct test 0: Using spaces."+ , testID = "displayBoundsTest0"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ (w,h) <- displayBounds t+ let row0 = replicate (fromEnum w) 'X' ++ "\n"+ rowH = replicate (fromEnum w - 1) 'X'+ rowN = "X" ++ replicate (fromEnum w - 2) ' ' ++ "X\n"+ image = row0 ++ (concat $ replicate (fromEnum h - 2) rowN) ++ rowH+ putStr image+ hFlush stdout+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = displayBoundsTestSummary True+ , confirmResults = genericOutputMatchConfirm+ }++displayBoundsTest1 = Test+ { testName = "Verify display bounds are correct test 0: Using cursor movement."+ , testID = "displayBoundsTest1"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ (w,h) <- displayBounds t+ setCursorPos t 0 0+ let row0 = replicate (fromEnum w) 'X' ++ "\n"+ putStr row0+ forM_ [1 .. h - 2] $ \y -> do+ setCursorPos t 0 y+ putStr "X"+ hFlush stdout+ setCursorPos t (w - 1) y+ putStr "X"+ hFlush stdout+ setCursorPos t 0 (h - 1)+ let rowH = replicate (fromEnum w - 1) 'X'+ putStr rowH+ hFlush stdout+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = displayBoundsTestSummary True+ , confirmResults = genericOutputMatchConfirm+ }++displayBoundsTest2 = Test+ { testName = "Verify display bounds are correct test 0: Using Image ops."+ , testID = "displayBoundsTest2"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ bounds@(w,h) <- displayBounds t+ let firstRow = horizCat $ replicate (fromEnum w) (char defAttr 'X')+ middleRows = vertCat $ replicate (fromEnum h - 2) middleRow+ middleRow = (char defAttr 'X') <|> backgroundFill (w - 2) 1 <|> (char defAttr 'X')+ endRow = firstRow+ image = firstRow <-> middleRows <-> endRow+ pic = (picForImage image) { picCursor = Cursor (w - 1) (h - 1) }+ d <- displayContext t bounds+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = displayBoundsTestSummary True+ , confirmResults = genericOutputMatchConfirm+ }++displayBoundsTest3 = Test+ { testName = "Verify display bounds are correct test 0: Hide cursor; Set cursor pos."+ , testID = "displayBoundsTest3"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ (w,h) <- displayBounds t+ hideCursor t+ setCursorPos t 0 0+ let row0 = replicate (fromEnum w) 'X'+ putStrLn row0+ forM_ [1 .. h - 2] $ \y -> do+ setCursorPos t 0 y+ putStr "X"+ hFlush stdout+ setCursorPos t (w - 1) y+ putStr "X"+ hFlush stdout+ setCursorPos t 0 (h - 1)+ let rowH = row0+ putStr rowH+ hFlush stdout+ getLine+ showCursor t+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = displayBoundsTestSummary False+ , confirmResults = genericOutputMatchConfirm+ }++displayBoundsTestSummary hasCursor = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+|]+ if hasCursor+ then putStr " 1. The cursor will be visible."+ else putStr " 1. The cursor will NOT be visible."+ putStr [s|++ 2. The border of the display will be outlined in Xs. + So if - and | represented the edge of the terminal window:+ |-------------|+ |XXXXXXXXXXXXX|+ |X X||]++ if hasCursor+ then putStr $ [s|++ |XXXXXXXXXXXXC| |]+ else putStr $ [s|++ |XXXXXXXXXXXXX| |]++ putStr $ [s|++ |-------------|++ ( Where C is the final position of the cursor. There may be an X drawn+ under the cursor. )+ 3. The display will remain in this state until return is pressed again.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]++genericOutputMatchConfirm = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults++-- Explicitely definethe bytes that encode each example text.+-- This avoids any issues with how the compiler represents string literals.+--+-- This document is UTF-8 encoded so the UTF-8 string is still included for+-- reference+--+-- It's assumed the compiler will at least not barf on UTF-8 encoded text in+-- comments ;-)+--+-- txt0 = ↑↑↓↓←→←→BA++utf8Txt0 :: [[Word8]]+utf8Txt0 = [ [ 0xe2 , 0x86 , 0x91 ]+ , [ 0xe2 , 0x86 , 0x91 ]+ , [ 0xe2 , 0x86 , 0x93 ]+ , [ 0xe2 , 0x86 , 0x93 ]+ , [ 0xe2 , 0x86 , 0x90 ]+ , [ 0xe2 , 0x86 , 0x92 ]+ , [ 0xe2 , 0x86 , 0x90 ]+ , [ 0xe2 , 0x86 , 0x92 ]+ , [ 0x42 ]+ , [ 0x41 ]+ ]++iso10646Txt0 :: String+iso10646Txt0 = map toEnum+ [ 8593 + , 8593+ , 8595+ , 8595+ , 8592+ , 8594+ , 8592+ , 8594+ , 66+ , 65+ ]++unicodeSingleWidth0 = Test+ { testName = "Verify terminal can display unicode single-width characters. (Direct UTF-8)"+ , testID = "unicodeSingleWidth0"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ hideCursor t+ withArrayLen (concat utf8Txt0) (flip $ hPutBuf stdout)+ hPutStr stdout "\n"+ hPutStr stdout "0123456789\n"+ hFlush stdout+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = unicodeSingleWidthSummary+ , confirmResults = genericOutputMatchConfirm+ }++unicodeSingleWidth1 = Test+ { testName = "Verify terminal can display unicode single-width characters. (Image ops)"+ , testID = "unicodeSingleWidth1"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = line0 <-> line1+ line0 = iso10646String defAttr iso10646Txt0+ line1 = string defAttr "0123456789"+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = unicodeSingleWidthSummary+ , confirmResults = genericOutputMatchConfirm+ }++unicodeSingleWidthSummary = putStr [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. Two horizontal lines of text will be displayed:+ a. The first will be a sequence of glyphs in UTF-8 encoding. Each glyph+ will occupy one column of space. The order and appearance of the glyphs+ will be:+ | column | appearance |+ ==========================+ | 0 | up arrow |+ | 1 | up arrow |+ | 2 | down arrow |+ | 3 | down arrow |+ | 4 | left arrow |+ | 5 | right arrow |+ | 6 | left arrow |+ | 7 | right arrow |+ | 8 | B |+ | 9 | A |+ ( see: http://en.wikipedia.org/wiki/Arrow_(symbol) )+ b. The second will be: 0123456789. ++Verify: + * The far right extent of the glyphs on both lines are equal; + * The glyphs are as described.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]++-- The second example is a unicode string containing double-width glyphs+-- 你好吗+utf8Txt1 :: [[Word8]]+utf8Txt1 = [ [0xe4,0xbd,0xa0]+ , [0xe5,0xa5,0xbd]+ , [0xe5,0x90,0x97]+ ]++iso10646Txt1 :: String+iso10646Txt1 = map toEnum [20320,22909,21527]++unicodeDoubleWidth0 = Test+ { testName = "Verify terminal can display unicode double-width characters. (Direct UTF-8)"+ , testID = "unicodeDoubleWidth0"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ hideCursor t+ withArrayLen (concat utf8Txt1) (flip $ hPutBuf stdout)+ hPutStr stdout "\n"+ hPutStr stdout "012345\n"+ hFlush stdout+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = unicodeDoubleWidthSummary+ , confirmResults = genericOutputMatchConfirm+ }++unicodeDoubleWidth1 = Test+ { testName = "Verify terminal can display unicode double-width characters. (Image ops)"+ , testID = "unicodeDoubleWidth1"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = line0 <-> line1+ line0 = iso10646String defAttr iso10646Txt1+ line1 = string defAttr "012345"+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = unicodeDoubleWidthSummary+ , confirmResults = genericOutputMatchConfirm+ }++unicodeDoubleWidthSummary = putStr [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. Two horizontal lines of text will be displayed:+ a. The first will be a sequence of glyphs in UTF-8 encoding. Each glyph+ will occupy two columns of space. The order and appearance of the glyphs+ will be:+ | column | appearance |+ ======================================+ | 0 | first half of ni3 |+ | 1 | second half of ni3 |+ | 2 | first half of hao3 |+ | 3 | second half of hao3 |+ | 4 | first half of ma |+ | 5 | second half of ma |+ b. The second will be: 012345. ++Verify: + * The far right extent of the glyphs on both lines are equal; + * The glyphs are as described.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]++allColors = zip [ black, red, green, yellow, blue, magenta, cyan, white ]+ [ "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" ]++allBrightColors + = zip [ brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite ]+ [ "bright black", "bright red", "bright green", "bright yellow", "bright blue", "bright magenta", "bright cyan", "bright white" ]++attributesTest0 = Test + { testName = "Character attributes: foreground colors."+ , testID = "attributesTest0"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = border <|> column0 <|> border <|> column1 <|> border+ column0 = vertCat $ map lineWithColor allColors+ border = vertCat $ replicate (length allColors) $ string defAttr " | "+ column1 = vertCat $ map (string defAttr . snd) allColors+ lineWithColor (c, cName) = string (defAttr `withForeColor` c) cName+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. 9 lines of text in two columns will be drawn. The first column will be a+ name of a standard color (for an 8 color terminal) rendered in that color.+ For instance, one line will be the word "magenta" and that word should be+ rendered in the magenta color. The second column will be the name of a+ standard color rendered with the default attributes.++Verify: + * In the first column: The foreground color matches the named color.+ * The second column: All text is rendered with the default attributes.+ * The vertical bars used in each line to mark the border of a column are+ lined up.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++attributesTest1 = Test + { testName = "Character attributes: background colors."+ , testID = "attributesTest1"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = border <|> column0 <|> border <|> column1 <|> border+ column0 = vertCat $ map lineWithColor allColors+ border = vertCat $ replicate (length allColors) $ string defAttr " | "+ column1 = vertCat $ map (string defAttr . snd) allColors+ lineWithColor (c, cName) = string (defAttr `withBackColor` c) cName+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. 9 lines of text in two columns will be drawn. The first column will+ contain be a name of a standard color for an 8 color terminal rendered with+ the default foreground color with a background the named color. For+ instance, one line will contain be the word "magenta" and the word should+ be rendered in the default foreground color over a magenta background. The+ second column will be the name of a standard color rendered with the default+ attributes.++Verify: + * The first column: The background color matches the named color.+ * The second column: All text is rendered with the default attributes.+ * The vertical bars used in each line to mark the border of a column are+ lined up.++Note: I haven't decided if, in this case, the background color should extend to+fills added for alignment. Right now the selected background color is only+applied to the background where the word is actually rendered. Since each word+is not of the same length VTY adds background fills to make the width of each+row effectively the same. These added fills are all currently rendered with the+default background pattern.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++attributesTest2 = Test + { testName = "Character attributes: Vivid foreground colors."+ , testID = "attributesTest2"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = horizCat [border, column0, border, column1, border, column2, border]+ border = vertCat $ replicate (length allColors) $ string defAttr " | "+ column0 = vertCat $ map lineWithColor0 allColors+ column1 = vertCat $ map lineWithColor1 allBrightColors+ column2 = vertCat $ map (string defAttr . snd) allColors+ lineWithColor0 (c, cName) = string (defAttr `withForeColor` c) cName+ lineWithColor1 (c, cName) = string (defAttr `withForeColor` c) cName+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. 9 lines of text in three columns will be drawn:+ a. The first column will be a name of a standard color (for an 8 color+ terminal) rendered with that color as the foreground color. + b. The next column will be also be the name of a standard color rendered+ with that color as the foreground color but the shade used should be+ more vivid than the shade used in the first column. + c. The final column will be the name of a color rendered with the+ default attributes.++For instance, one line will be the word "magenta" and that word should be+rendered in the magenta color. ++I'm not actually sure exactly what "vivid" means in this context. For xterm the+vivid colors are brighter. ++Verify: + * The first column: The foreground color matches the named color.+ * The second column: The foreground color matches the named color but is+ more vivid than the color used in the first column. + * The third column: All text is rendered with the default attributes.+ * The vertical bars used in each line to mark the border of a column are+ lined up.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++attributesTest3 = Test + { testName = "Character attributes: Vivid background colors."+ , testID = "attributesTest3"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = horizCat [border, column0, border, column1, border, column2, border]+ border = vertCat $ replicate (length allColors) $ string defAttr " | "+ column0 = vertCat $ map lineWithColor0 allColors+ column1 = vertCat $ map lineWithColor1 allBrightColors+ column2 = vertCat $ map (string defAttr . snd) allColors+ lineWithColor0 (c, cName) = string (defAttr `withBackColor` c) cName+ lineWithColor1 (c, cName) = string (defAttr `withBackColor` c) cName+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. 9 lines of text in three columns will be drawn:+ a. The first column will contain be a name of a standard color for an 8+ color terminal rendered with the default foreground color with a+ background the named color. + b. The first column will contain be a name of a standard color for an 8+ color terminal rendered with the default foreground color with the+ background a vivid version of the named color. + c. The third column will be the name of a standard color rendered with+ the default attributes.+ +For instance, one line will contain be the word "magenta" and the word should+be rendered in the default foreground color over a magenta background. ++I'm not actually sure exactly what "vivid" means in this context. For xterm the+vivid colors are brighter.++Verify: + * The first column: The background color matches the named color.+ * The second column: The background color matches the named color and is+ more vivid than the color used in the first column. + * The third column column: All text is rendered with the default attributes.+ * The vertical bars used in each line to mark the border of a column are+ lined up.++Note: I haven't decided if, in this case, the background color should extend to+fills added for alignment. Right now the selected background color is only+applied to the background where the word is actually rendered. Since each word+is not of the same length VTY adds background fills to make the width of each+row effectively the same. These added fills are all currently rendered with the+default background pattern.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++attrCombos = + [ ( "default", id )+ , ( "bold", flip withStyle bold )+ , ( "blink", flip withStyle blink )+ , ( "underline", flip withStyle underline )+ , ( "bold + blink", flip withStyle (bold + blink) )+ , ( "bold + underline", flip withStyle (bold + underline) )+ , ( "underline + blink", flip withStyle (underline + blink) )+ , ( "bold + blink + underline", flip withStyle (bold + blink + underline) )+ ]++attributesTest4 = Test + { testName = "Character attributes: Bold; Blink; Underline."+ , testID = "attributesTest4"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = horizCat [border, column0, border, column1, border]+ border = vertCat $ replicate (length attrCombos) $ string defAttr " | "+ column0 = vertCat $ map lineWithAttrs attrCombos+ column1 = vertCat $ map (string defAttr . fst) attrCombos+ lineWithAttrs (desc, attrF) = string (attrF defAttr) desc+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. 8 rows of text in two columns. + The rows will contain the following text:+ default+ bold + blink+ underline+ bold + blink+ bold + underline+ underline + blink+ bold + blink + underline+ The first column will be rendered with the described attributes. The second+ column will be rendered with the default attributes.+ +Verify: + * The vertical bars used in each line to mark the border of a column are+ lined up.+ * The text in the first column is rendered as described.++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++attributesTest5 = Test + { testName = "Character attributes: 240 color palette"+ , testID = "attributesTest5"+ , testAction = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ let pic = picForImage image+ image = vertCat $ map horizCat $ splitColorImages colorImages+ colorImages = map (\i -> string (currentAttr `withBackColor` Color240 i) " ") [0..239]+ splitColorImages [] = []+ splitColorImages is = (take 20 is ++ [string defAttr " "]) : (splitColorImages (drop 20 is))+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ , printSummary = do+ putStr $ [s|+Once return is pressed:+ 0. The screen will be cleared.+ 1. The cursor will be hidden.+ 2. A 20 character wide and 12 row high block of color squares. This should look like a palette+ of some sort. I'm not exactly sure if all color terminals use the same palette. I doubt it...++Verify: ++After return is pressed for the second time:+ 0. The screen containing the test summary should be restored.+ 1. The cursor should be visible.+|]+ , confirmResults = do+ putStr $ [s|+Did the test output match the description?+|]+ defaultSuccessConfirmResults+ }++inlineTest0 = Test+ { testName = "Verify styled output can be performed without clearing the screen."+ , testID = "inlineTest0"+ , testAction = do+ putStrLn "line 1."+ putAttrChange_ $ backColor red >> applyStyle underline+ putStrLn "line 2."+ putAttrChange_ $ defaultAll+ putStrLn "line 3."+ , printSummary = putStr $ [s|+lines are in order.+The second line "line 2" should have a red background and the text underline.+The third line "line 3" should be drawn in the same style as the first line.+|]++ , confirmResults = genericOutputMatchConfirm+ }++inlineTest1 = Test+ { testName = "Verify styled output can be performed without clearing the screen."+ , testID = "inlineTest1"+ , testAction = do+ putStr "Not styled. "+ putAttrChange_ $ backColor red >> applyStyle underline+ putStr " Styled! "+ putAttrChange_ $ defaultAll+ putStrLn "Not styled."+ , printSummary = putStr $ [s|+|]++ , confirmResults = genericOutputMatchConfirm+ }++inlineTest2 = Test+ { testName = "Verify styled output can be performed without clearing the screen."+ , testID = "inlineTest1"+ , testAction = do+ putStr "Not styled. "+ putAttrChange_ $ backColor red >> applyStyle underline+ putStr " Styled! "+ putAttrChange_ $ defaultAll+ putStr "Not styled.\n"+ , printSummary = putStr $ [s|+|]+ , confirmResults = genericOutputMatchConfirm+ }++cursorHideTest0 :: Test+cursorHideTest0 = Test+ { testName = "Verify the cursor is hid and re-shown. issue #7"+ , testID = "cursorHideTest0"+ , testAction = do+ vty <- mkVty def+ showCursor $ outputIface vty+ setCursorPos (outputIface vty) 5 5+ nextEvent vty+ hideCursor $ outputIface vty+ nextEvent vty+ shutdown vty+ return ()+ , printSummary = putStr $ [s|+ 1. verify the cursor is displayed.+ 2. press enter+ 3. verify the cursor is hid.+ 4. press enter.+ 5. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++outputImageAndWait :: Image -> IO ()+outputImageAndWait image = do+ let pic = picForImage image+ outputPicAndWait pic++outputPicAndWait :: Picture -> IO ()+outputPicAndWait pic = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ d <- displayBounds t >>= displayContext t+ outputPicture d pic+ getLine+ releaseDisplay t+ releaseTerminal t+ return ()+ +vertCropTest0 :: Test+vertCropTest0 = Test+ { testName = "Verify bottom cropping works as expected with single column chars"+ , testID = "cropTest0"+ , testAction = do+ let block0 = cropBottom 2 $ vertCat $ map (string defAttr) lorumIpsum+ block1 = vertCat $ map (string defAttr) $ take 2 lorumIpsum+ image = block0 <-> backgroundFill 10 2 <-> block1+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the two text blocks are identical.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++vertCropTest1 :: Test+vertCropTest1 = Test+ { testName = "Verify bottom cropping works as expected with double column chars"+ , testID = "cropTest0"+ , testAction = do+ let block0 = cropBottom 2 $ vertCat $ map (string defAttr) lorumIpsumChinese+ block1 = vertCat $ map (string defAttr) $ take 2 lorumIpsumChinese+ image = block0 <-> backgroundFill 10 2 <-> block1+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the two text blocks are identical.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++vertCropTest2 :: Test+vertCropTest2 = Test+ { testName = "Verify top cropping works as expected with single column chars"+ , testID = "cropTest2"+ , testAction = do+ let block0 = cropTop 2 $ vertCat $ map (string defAttr) lorumIpsum+ block1 = vertCat $ map (string defAttr) $ drop (length lorumIpsum - 2) lorumIpsum+ image = block0 <-> backgroundFill 10 2 <-> block1+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the two text blocks are identical.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++vertCropTest3 :: Test+vertCropTest3 = Test+ { testName = "Verify top cropping works as expected with double column chars"+ , testID = "cropTest0"+ , testAction = do+ let block0 = cropTop 2 $ vertCat $ map (string defAttr) lorumIpsumChinese+ block1 = vertCat $ map (string defAttr) $ drop (length lorumIpsumChinese - 2 ) lorumIpsumChinese+ image = block0 <-> backgroundFill 10 2 <-> block1+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the two text blocks are identical.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++horizCropTest0 :: Test+horizCropTest0 = Test+ { testName = "Verify right cropping works as expected with single column chars"+ , testID = "cropTest0"+ , testAction = do+ let baseImage = vertCat $ map (string defAttr) lorumIpsum+ croppedImage = cropRight (imageWidth baseImage `div` 2) baseImage + image = baseImage <-> backgroundFill 10 2 <-> croppedImage+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the bottom text block is about half the width of the top text block.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++horizCropTest1 :: Test+horizCropTest1 = Test+ { testName = "Verify right cropping works as expected with double column chars"+ , testID = "cropTest0"+ , testAction = do+ let baseImage = vertCat $ map (string defAttr) lorumIpsumChinese+ croppedImage = cropRight (imageWidth baseImage `div` 2) baseImage + image = baseImage <-> backgroundFill 10 2 <-> croppedImage+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the bottom text block is the left half of the top block. Ellipses on the right edge are OK.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++horizCropTest2 :: Test+horizCropTest2 = Test+ { testName = "Verify left cropping works as expected with single column chars"+ , testID = "cropTest0"+ , testAction = do+ let baseImage = vertCat $ map (string defAttr) lorumIpsum+ croppedImage = cropLeft (imageWidth baseImage `div` 2) baseImage + image = baseImage <-> backgroundFill 10 2 <-> croppedImage+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the bottom text block is the right half of the top text block.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++horizCropTest3 :: Test+horizCropTest3 = Test+ { testName = "Verify right cropping works as expected with double column chars"+ , testID = "cropTest0"+ , testAction = do+ let baseImage = vertCat $ map (string defAttr) lorumIpsumChinese+ croppedImage = cropLeft (imageWidth baseImage `div` 2) baseImage + image = baseImage <-> backgroundFill 10 2 <-> croppedImage+ outputImageAndWait image+ , printSummary = putStr $ [s|+ 1. Verify the bottom text block is the right half of the top block. Ellipses on the left edge are OK.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++layer0 :: Test+layer0 = Test+ { testName = "verify layer 0"+ , testID = "layer0"+ , testAction = do+ let upperImage = vertCat $ map (string defAttr) lorumIpsumChinese+ lowerImage = vertCat $ map (string defAttr) lorumIpsum+ p = picForLayers [upperImage, lowerImage]+ outputPicAndWait p+ , printSummary = putStr $ [s|+ 1. Verify the text block appears to be Chinese text placed on top Latin text.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++layer1 :: Test+layer1 = Test+ { testName = "verify layer 1"+ , testID = "layer1"+ , testAction = do+ let upperImage = vertCat $ map (string defAttr) lorumIpsumChinese+ block = resize 10 10 upperImage+ layer0 = vertCat $ map (string defAttr) lorumIpsum+ layer1 = charFill (defAttr `withBackColor` blue) '#' 1000 1000+ cheesyAnim0 block [layer0, layer1]+ , printSummary = putStr $ [s|+ 1. Verify the text block appears to be Chinese text moving on top a Latin text.+ Which is all on a background of '#' characters over blue.+ 2. press enter.+ 3. the display should return to the state before the test.+|]+ , confirmResults = genericOutputMatchConfirm+ }++cheesyAnim0 :: Image -> [Image] -> IO ()+cheesyAnim0 i background = do+ t <- outputForCurrentTerminal def+ reserveDisplay t+ bounds <- displayBounds t+ d <- displayContext t bounds+ forM_ [0..100] $ \t -> do+ let i_offset = translate (t `mod` fst bounds)+ (t `div` 2 `mod` snd bounds)+ i+ let pic = picForLayers $ i_offset : background+ outputPicture d pic+ threadDelay 50000+ releaseDisplay t+ releaseTerminal t+ return ()++lorumIpsum :: [String]+lorumIpsum = lines [s|+Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,+totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,+sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius+modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea+commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil+molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?+|]++lorumIpsumChinese :: [String]+lorumIpsumChinese = lines [s|+輐銛 螷蟞覮 裌覅詵 暕 鴅噮 槶 惝掭掝 婸媥媕 耏胠臿, 汫汭沎 忕汌卣 蚡袀 僣 蒮 瀁瀎瀊 渮湸湤 緌翢,+腠腶舝 糲蘥蠩 樏殣氀 蒮 蹢鎒 滍 鸄齴 櫧櫋瀩 鬄鵊鵙 莃荶衒, 毸溠 橀 簎艜薤 莃荶衒 翣聜蒢+斔櫅檷 晛桼桾 拻敁柧 犿玒 膣, 墐 笓粊紒 bacon 鼀齕, 蔝蓶蓨 顊顃餭 姴怤 骱 暕 蹢鎒鎛 藒襓謥 鄻鎟霣+鬎鯪, 鐩闤 硻禂稢 谾踘遳 撱 赲 迡 箷 蛃袚觙 萇雊蜩 壿嫷 鋡 縢羱聬 跐鉠鉣 蔝蓶蓨 匢奾灱 溮煡煟 雥齆犪+蔰 虈觿, 腷腯葹 鍹餳駷 蛚袲褁蜸 皯竻 瀁瀎 蜭蜸覟 梪涫湴 揗斝湁 毼+|]+
+ vty-examples.cabal view
@@ -0,0 +1,114 @@+name: vty-examples+version: 5.0.0+license: BSD3+license-file: ../LICENSE+author: AUTHORS+maintainer: Corey O'Connor (coreyoconnor@gmail.com)+homepage: https://github.com/coreyoconnor/vty+category: User Interfaces+synopsis: Examples programs using the vty library.+description:+ vty is terminal GUI library in the niche of ncurses. It is intended to be easy to use, have no+ confusing corner cases, and good support for common terminal types.+ .+ vty-interactive-terminal-test - interactive test. Useful for building a bug report for vtys author.+ vty-event-echo - view a input event log for vty. Example of interacting with user.+ vty-rouge - A bad rouge-like game. Go from the entrance to exit. Example of layers+ vty-benchmark - benchmarks vty. A series of tests that push random pictures to the terminal.+ .+ © Corey O'Connor; BSD3 license.+cabal-version: >= 1.18.0+build-type: Simple++executable vty-interactive-terminal-test+ main-is: interactive_terminal_test.hs++ default-language: Haskell2010+ default-extensions: ScopedTypeVariables+ ghc-options: -threaded++ build-depends: vty == 5.*,+ base >= 4 && < 5,+ bytestring,+ containers,+ data-default >= 0.5.3,+ deepseq >= 1.1 && < 1.4,+ lens,+ mtl >= 1.1.1.0 && < 2.2,+ parallel >= 2.2 && < 3.3,+ parsec >= 2 && < 4,+ string-qq,+ terminfo >= 0.3 && < 0.5,+ text >= 0.11.3,+ unix,+ utf8-string >= 0.3 && < 0.4,+ vector >= 0.7++executable vty-event-echo+ main-is: EventEcho.hs++ default-language: Haskell2010+ default-extensions: ScopedTypeVariables+ ghc-options: -threaded++ build-depends: vty == 5.*,+ base >= 4 && < 5,+ array >= 0.4 && < 2.0,+ bytestring,+ containers,+ data-default >= 0.5.3,+ lens,+ mtl >= 1.1.1.0 && < 2.2,+ parallel >= 2.2 && < 3.3,+ text >= 0.11.3,+ utf8-string >= 0.3 && < 0.4,+ vector >= 0.7++executable vty-rouge+ main-is: Rouge.hs++ default-language: Haskell2010+ default-extensions: ScopedTypeVariables+ ghc-options: -threaded++ build-depends: vty == 5.*,+ base >= 4 && < 5,+ array >= 0.4 && < 2.0,+ bytestring,+ containers,+ data-default >= 0.5.3,+ lens,+ mtl >= 1.1.1.0 && < 2.2,+ parallel >= 2.2 && < 3.3,+ random >= 1.0 && < 2.0,+ text >= 0.11.3,+ utf8-string >= 0.3 && < 0.4,+ vector >= 0.7++executable vty-benchmark+ main-is: benchmark.hs++ default-language: Haskell2010+ default-extensions: ScopedTypeVariables+ ghc-options: -threaded++ build-depends: vty == 5.*,+ base >= 4 && < 5,+ bytestring,+ Cabal == 1.18.*,+ containers,+ data-default >= 0.5.3,+ deepseq >= 1.1 && < 1.4,+ lens,+ mtl >= 1.1.1.0 && < 2.2,+ parallel >= 2.2 && < 3.3,+ parsec >= 2 && < 4,+ QuickCheck >= 2.4,+ random == 1.0.*,+ string-qq,+ terminfo >= 0.3 && < 0.5,+ text >= 0.11.3,+ unix,+ utf8-string >= 0.3 && < 0.4,+ vector >= 0.7+