|
Packit |
1d8052 |
-- | Terminal control. Internal QuickCheck module.
|
|
Packit |
1d8052 |
module Test.QuickCheck.Text
|
|
Packit |
1d8052 |
( Str(..)
|
|
Packit |
1d8052 |
, ranges
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
, number
|
|
Packit |
1d8052 |
, short
|
|
Packit |
1d8052 |
, showErr
|
|
Packit |
1d8052 |
, oneLine
|
|
Packit |
1d8052 |
, isOneLine
|
|
Packit |
1d8052 |
, bold
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
, newTerminal
|
|
Packit |
1d8052 |
, withStdioTerminal
|
|
Packit |
1d8052 |
, withNullTerminal
|
|
Packit |
1d8052 |
, terminalOutput
|
|
Packit |
1d8052 |
, handle
|
|
Packit |
1d8052 |
, Terminal
|
|
Packit |
1d8052 |
, putTemp
|
|
Packit |
1d8052 |
, putPart
|
|
Packit |
1d8052 |
, putLine
|
|
Packit |
1d8052 |
)
|
|
Packit |
1d8052 |
where
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
--------------------------------------------------------------------------
|
|
Packit |
1d8052 |
-- imports
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
import System.IO
|
|
Packit |
1d8052 |
( hFlush
|
|
Packit |
1d8052 |
, hPutStr
|
|
Packit |
1d8052 |
, stdout
|
|
Packit |
1d8052 |
, stderr
|
|
Packit |
1d8052 |
, Handle
|
|
Packit |
1d8052 |
, BufferMode (..)
|
|
Packit |
1d8052 |
, hGetBuffering
|
|
Packit |
1d8052 |
, hSetBuffering
|
|
Packit |
1d8052 |
, hIsTerminalDevice
|
|
Packit |
1d8052 |
)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
import Data.IORef
|
|
Packit |
1d8052 |
import Test.QuickCheck.Exception
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
--------------------------------------------------------------------------
|
|
Packit |
1d8052 |
-- literal string
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
newtype Str = MkStr String
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
instance Show Str where
|
|
Packit |
1d8052 |
show (MkStr s) = s
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
ranges :: (Show a, Integral a) => a -> a -> Str
|
|
Packit |
1d8052 |
ranges k n = MkStr (show n' ++ " -- " ++ show (n'+k-1))
|
|
Packit |
1d8052 |
where
|
|
Packit |
1d8052 |
n' = k * (n `div` k)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
--------------------------------------------------------------------------
|
|
Packit |
1d8052 |
-- formatting
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
number :: Int -> String -> String
|
|
Packit |
1d8052 |
number n s = show n ++ " " ++ s ++ if n == 1 then "" else "s"
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
short :: Int -> String -> String
|
|
Packit |
1d8052 |
short n s
|
|
Packit |
1d8052 |
| n < k = take (n-2-i) s ++ ".." ++ drop (k-i) s
|
|
Packit |
1d8052 |
| otherwise = s
|
|
Packit |
1d8052 |
where
|
|
Packit |
1d8052 |
k = length s
|
|
Packit |
1d8052 |
i = if n >= 5 then 3 else 0
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
showErr :: Show a => a -> String
|
|
Packit |
1d8052 |
showErr = unwords . words . show
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
oneLine :: String -> String
|
|
Packit |
1d8052 |
oneLine = unwords . words
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
isOneLine :: String -> Bool
|
|
Packit |
1d8052 |
isOneLine xs = '\n' `notElem` xs
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
bold :: String -> String
|
|
Packit |
1d8052 |
-- not portable:
|
|
Packit |
1d8052 |
--bold s = "\ESC[1m" ++ s ++ "\ESC[0m"
|
|
Packit |
1d8052 |
bold s = s -- for now
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
--------------------------------------------------------------------------
|
|
Packit |
1d8052 |
-- putting strings
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
data Terminal
|
|
Packit |
1d8052 |
= MkTerminal (IORef ShowS) (IORef Int) (String -> IO ()) (String -> IO ())
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
newTerminal :: (String -> IO ()) -> (String -> IO ()) -> IO Terminal
|
|
Packit |
1d8052 |
newTerminal out err =
|
|
Packit |
1d8052 |
do res <- newIORef (showString "")
|
|
Packit |
1d8052 |
tmp <- newIORef 0
|
|
Packit |
1d8052 |
return (MkTerminal res tmp out err)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
withBuffering :: IO a -> IO a
|
|
Packit |
1d8052 |
withBuffering action = do
|
|
Packit |
1d8052 |
mode <- hGetBuffering stderr
|
|
Packit |
1d8052 |
-- By default stderr is unbuffered. This is very slow, hence we explicitly
|
|
Packit |
1d8052 |
-- enable line buffering.
|
|
Packit |
1d8052 |
hSetBuffering stderr LineBuffering
|
|
Packit |
1d8052 |
action `finally` hSetBuffering stderr mode
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
withStdioTerminal :: (Terminal -> IO a) -> IO a
|
|
Packit |
1d8052 |
withStdioTerminal action = do
|
|
Packit |
1d8052 |
isatty <- hIsTerminalDevice stderr
|
|
Packit |
1d8052 |
let err = if isatty then handle stderr else const (return ())
|
|
Packit |
1d8052 |
withBuffering (newTerminal (handle stdout) err >>= action)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
withNullTerminal :: (Terminal -> IO a) -> IO a
|
|
Packit |
1d8052 |
withNullTerminal action =
|
|
Packit |
1d8052 |
newTerminal (const (return ())) (const (return ())) >>= action
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
terminalOutput :: Terminal -> IO String
|
|
Packit |
1d8052 |
terminalOutput (MkTerminal res _ _ _) = fmap ($ "") (readIORef res)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
handle :: Handle -> String -> IO ()
|
|
Packit |
1d8052 |
handle h s = do
|
|
Packit |
1d8052 |
hPutStr h s
|
|
Packit |
1d8052 |
hFlush h
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
flush :: Terminal -> IO ()
|
|
Packit |
1d8052 |
flush (MkTerminal _ tmp _ err) =
|
|
Packit |
1d8052 |
do n <- readIORef tmp
|
|
Packit |
1d8052 |
writeIORef tmp 0
|
|
Packit |
1d8052 |
err (replicate n ' ' ++ replicate n '\b')
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
putPart, putTemp, putLine :: Terminal -> String -> IO ()
|
|
Packit |
1d8052 |
putPart tm@(MkTerminal res _ out _) s =
|
|
Packit |
1d8052 |
do flush tm
|
|
Packit |
1d8052 |
force s
|
|
Packit |
1d8052 |
out s
|
|
Packit |
1d8052 |
modifyIORef res (. showString s)
|
|
Packit |
1d8052 |
where
|
|
Packit |
1d8052 |
force :: [a] -> IO ()
|
|
Packit |
1d8052 |
force = evaluate . seqList
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
seqList :: [a] -> ()
|
|
Packit |
1d8052 |
seqList [] = ()
|
|
Packit |
1d8052 |
seqList (x:xs) = x `seq` seqList xs
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
putLine tm s = putPart tm (s ++ "\n")
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
putTemp tm@(MkTerminal _ tmp _ err) s =
|
|
Packit |
1d8052 |
do flush tm
|
|
Packit |
1d8052 |
err (s ++ [ '\b' | _ <- s ])
|
|
Packit |
1d8052 |
modifyIORef tmp (+ length s)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
--------------------------------------------------------------------------
|
|
Packit |
1d8052 |
-- the end.
|