{-# OPTIONS_HADDOCK hide #-}
module Test.QuickCheck.Text
( Str(..)
, ranges
, number
, short
, showErr
, oneLine
, isOneLine
, bold
, ljust, rjust, centre, lpercent, rpercent, lpercentage, rpercentage
, drawTable, Cell(..)
, paragraphs
, newTerminal
, withStdioTerminal
, withHandleTerminal
, withNullTerminal
, terminalOutput
, handle
, Terminal
, putTemp
, putPart
, putLine
)
where
import System.IO
( hFlush
, hPutStr
, stdout
, stderr
, Handle
, BufferMode (..)
, hGetBuffering
, hSetBuffering
, hIsTerminalDevice
)
import Data.IORef
import Data.List
import Text.Printf
import Test.QuickCheck.Exception
newtype Str = MkStr String
instance Show Str where
show :: Str -> String
show (MkStr s :: String
s) = String
s
ranges :: (Show a, Integral a) => a -> a -> Str
ranges :: a -> a -> Str
ranges k :: a
k n :: a
n = String -> Str
MkStr (a -> String
forall a. Show a => a -> String
show a
n' String -> ShowS
forall a. [a] -> [a] -> [a]
++ " -- " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show (a
n'a -> a -> a
forall a. Num a => a -> a -> a
+a
ka -> a -> a
forall a. Num a => a -> a -> a
-1))
where
n' :: a
n' = a
k a -> a -> a
forall a. Num a => a -> a -> a
* (a
n a -> a -> a
forall a. Integral a => a -> a -> a
`div` a
k)
number :: Int -> String -> String
number :: Int -> ShowS
number n :: Int
n s :: String
s = Int -> String
forall a. Show a => a -> String
show Int
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 1 then "" else "s"
short :: Int -> String -> String
short :: Int -> ShowS
short n :: Int
n s :: String
s
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
k = Int -> ShowS
forall a. Int -> [a] -> [a]
take (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-2Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
i) String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ ".." String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
forall a. Int -> [a] -> [a]
drop (Int
kInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
i) String
s
| Bool
otherwise = String
s
where
k :: Int
k = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s
i :: Int
i = if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 5 then 3 else 0
showErr :: Show a => a -> String
showErr :: a -> String
showErr = [String] -> String
unwords ([String] -> String) -> (a -> [String]) -> a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
words (String -> [String]) -> (a -> String) -> a -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show
oneLine :: String -> String
oneLine :: ShowS
oneLine = [String] -> String
unwords ([String] -> String) -> (String -> [String]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
words
isOneLine :: String -> Bool
isOneLine :: String -> Bool
isOneLine xs :: String
xs = '\n' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` String
xs
ljust :: Int -> ShowS
ljust n :: Int
n xs :: String
xs = String
xs String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
xs) ' '
rjust :: Int -> ShowS
rjust n :: Int
n xs :: String
xs = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
xs) ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
xs
centre :: Int -> ShowS
centre n :: Int
n xs :: String
xs =
Int -> ShowS
ljust Int
n ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
Int -> Char -> String
forall a. Int -> a -> [a]
replicate ((Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
xs) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 2) ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
xs
lpercent, rpercent :: (Integral a, Integral b) => a -> b -> String
lpercent :: a -> b -> String
lpercent n :: a
n k :: b
k =
Double -> b -> String
forall a. Integral a => Double -> a -> String
lpercentage (a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ b -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral b
k) b
k
rpercent :: a -> b -> String
rpercent n :: a
n k :: b
k =
Double -> b -> String
forall a. Integral a => Double -> a -> String
rpercentage (a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ b -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral b
k) b
k
lpercentage, rpercentage :: Integral a => Double -> a -> String
lpercentage :: Double -> a -> String
lpercentage p :: Double
p n :: a
n =
String -> Integer -> Double -> String
forall r. PrintfType r => String -> r
printf "%.*f" Integer
places (100Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
p) String -> ShowS
forall a. [a] -> [a] -> [a]
++ "%"
where
places :: Integer
places :: Integer
places =
Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase 10 (a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n) Double -> Double -> Double
forall a. Num a => a -> a -> a
- 2 :: Double) Integer -> Integer -> Integer
forall a. Ord a => a -> a -> a
`max` 0
rpercentage :: Double -> a -> String
rpercentage p :: Double
p n :: a
n = String
padding String -> ShowS
forall a. [a] -> [a] -> [a]
++ Double -> a -> String
forall a. Integral a => Double -> a -> String
lpercentage Double
p a
n
where
padding :: String
padding = if Double
p Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< 0.1 then " " else ""
data Cell = LJust String | RJust String | Centred String deriving Int -> Cell -> ShowS
[Cell] -> ShowS
Cell -> String
(Int -> Cell -> ShowS)
-> (Cell -> String) -> ([Cell] -> ShowS) -> Show Cell
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Cell] -> ShowS
$cshowList :: [Cell] -> ShowS
show :: Cell -> String
$cshow :: Cell -> String
showsPrec :: Int -> Cell -> ShowS
$cshowsPrec :: Int -> Cell -> ShowS
Show
text :: Cell -> String
text :: Cell -> String
text (LJust xs :: String
xs) = String
xs
text (RJust xs :: String
xs) = String
xs
text (Centred xs :: String
xs) = String
xs
flattenRows :: [[Cell]] -> [String]
flattenRows :: [[Cell]] -> [String]
flattenRows rows :: [[Cell]]
rows = ([Cell] -> String) -> [[Cell]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [Cell] -> String
row [[Cell]]
rows
where
cols :: [[Cell]]
cols = [[Cell]] -> [[Cell]]
forall a. [[a]] -> [[a]]
transpose [[Cell]]
rows
widths :: [Int]
widths = ([Cell] -> Int) -> [[Cell]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ([Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Int] -> Int) -> ([Cell] -> [Int]) -> [Cell] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Cell -> Int) -> [Cell] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (Cell -> String) -> Cell -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cell -> String
text)) [[Cell]]
cols
row :: [Cell] -> String
row cells :: [Cell]
cells = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse " " ((Int -> Cell -> String) -> [Int] -> [Cell] -> [String]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Cell -> String
cell [Int]
widths [Cell]
cells))
cell :: Int -> Cell -> String
cell n :: Int
n (LJust xs :: String
xs) = Int -> ShowS
ljust Int
n String
xs
cell n :: Int
n (RJust xs :: String
xs) = Int -> ShowS
rjust Int
n String
xs
cell n :: Int
n (Centred xs :: String
xs) = Int -> ShowS
centre Int
n String
xs
drawTable :: [String] -> [[Cell]] -> [String]
drawTable :: [String] -> [[Cell]] -> [String]
drawTable headers :: [String]
headers table :: [[Cell]]
table =
[String
line] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[Char -> Char -> ShowS
border '|' ' ' String
header | String
header <- [String]
headers] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[String
line | Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
headers) Bool -> Bool -> Bool
&& Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
rows)] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[Char -> Char -> ShowS
border '|' ' ' String
row | String
row <- [String]
rows] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
[String
line]
where
rows :: [String]
rows = [[Cell]] -> [String]
flattenRows [[Cell]]
table
headerwidth :: Int
headerwidth = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (0Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:(String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
headers)
bodywidth :: Int
bodywidth = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (0Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:(String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
rows)
width :: Int
width = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
headerwidth Int
bodywidth
line :: String
line = Char -> Char -> ShowS
border '+' '-' ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
width '-'
border :: Char -> Char -> ShowS
border x :: Char
x y :: Char
y xs :: String
xs = [Char
x, Char
y] String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
centre Int
width String
xs String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char
y, Char
x]
paragraphs :: [[String]] -> [String]
paragraphs :: [[String]] -> [String]
paragraphs = [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[String]] -> [String])
-> ([[String]] -> [[String]]) -> [[String]] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [[String]] -> [[String]]
forall a. a -> [a] -> [a]
intersperse [""] ([[String]] -> [[String]])
-> ([[String]] -> [[String]]) -> [[String]] -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> Bool) -> [[String]] -> [[String]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([String] -> Bool) -> [String] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null)
bold :: String -> String
bold :: ShowS
bold s :: String
s = String
s
data Terminal
= MkTerminal (IORef ShowS) (IORef Int) (String -> IO ()) (String -> IO ())
newTerminal :: (String -> IO ()) -> (String -> IO ()) -> IO Terminal
newTerminal :: (String -> IO ()) -> (String -> IO ()) -> IO Terminal
newTerminal out :: String -> IO ()
out err :: String -> IO ()
err =
do IORef ShowS
res <- ShowS -> IO (IORef ShowS)
forall a. a -> IO (IORef a)
newIORef (String -> ShowS
showString "")
IORef Int
tmp <- Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef 0
Terminal -> IO Terminal
forall (m :: * -> *) a. Monad m => a -> m a
return (IORef ShowS
-> IORef Int -> (String -> IO ()) -> (String -> IO ()) -> Terminal
MkTerminal IORef ShowS
res IORef Int
tmp String -> IO ()
out String -> IO ()
err)
withBuffering :: IO a -> IO a
withBuffering :: IO a -> IO a
withBuffering action :: IO a
action = do
BufferMode
mode <- Handle -> IO BufferMode
hGetBuffering Handle
stderr
Handle -> BufferMode -> IO ()
hSetBuffering Handle
stderr BufferMode
LineBuffering
IO a
action IO a -> IO () -> IO a
forall a b. IO a -> IO b -> IO a
`finally` Handle -> BufferMode -> IO ()
hSetBuffering Handle
stderr BufferMode
mode
withHandleTerminal :: Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
withHandleTerminal :: Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
withHandleTerminal outh :: Handle
outh merrh :: Maybe Handle
merrh action :: Terminal -> IO a
action = do
let
err :: String -> IO ()
err =
case Maybe Handle
merrh of
Nothing -> IO () -> String -> IO ()
forall a b. a -> b -> a
const (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
Just errh :: Handle
errh -> Handle -> String -> IO ()
handle Handle
errh
(String -> IO ()) -> (String -> IO ()) -> IO Terminal
newTerminal (Handle -> String -> IO ()
handle Handle
outh) String -> IO ()
err IO Terminal -> (Terminal -> IO a) -> IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Terminal -> IO a
action
withStdioTerminal :: (Terminal -> IO a) -> IO a
withStdioTerminal :: (Terminal -> IO a) -> IO a
withStdioTerminal action :: Terminal -> IO a
action = do
Bool
isatty <- Handle -> IO Bool
hIsTerminalDevice Handle
stderr
if Bool
isatty then
IO a -> IO a
forall a. IO a -> IO a
withBuffering (Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
forall a. Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
withHandleTerminal Handle
stdout (Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
stderr) Terminal -> IO a
action)
else
IO a -> IO a
forall a. IO a -> IO a
withBuffering (Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
forall a. Handle -> Maybe Handle -> (Terminal -> IO a) -> IO a
withHandleTerminal Handle
stdout Maybe Handle
forall a. Maybe a
Nothing Terminal -> IO a
action)
withNullTerminal :: (Terminal -> IO a) -> IO a
withNullTerminal :: (Terminal -> IO a) -> IO a
withNullTerminal action :: Terminal -> IO a
action =
(String -> IO ()) -> (String -> IO ()) -> IO Terminal
newTerminal (IO () -> String -> IO ()
forall a b. a -> b -> a
const (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())) (IO () -> String -> IO ()
forall a b. a -> b -> a
const (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())) IO Terminal -> (Terminal -> IO a) -> IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Terminal -> IO a
action
terminalOutput :: Terminal -> IO String
terminalOutput :: Terminal -> IO String
terminalOutput (MkTerminal res :: IORef ShowS
res _ _ _) = (ShowS -> String) -> IO ShowS -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ "") (IORef ShowS -> IO ShowS
forall a. IORef a -> IO a
readIORef IORef ShowS
res)
handle :: Handle -> String -> IO ()
handle :: Handle -> String -> IO ()
handle h :: Handle
h s :: String
s = do
Handle -> String -> IO ()
hPutStr Handle
h String
s
Handle -> IO ()
hFlush Handle
h
putPart, putTemp, putLine :: Terminal -> String -> IO ()
putPart :: Terminal -> String -> IO ()
putPart tm :: Terminal
tm@(MkTerminal res :: IORef ShowS
res _ out :: String -> IO ()
out _) s :: String
s =
do Terminal -> String -> IO ()
putTemp Terminal
tm ""
String -> IO ()
forall a. [a] -> IO ()
force String
s
String -> IO ()
out String
s
IORef ShowS -> (ShowS -> ShowS) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef IORef ShowS
res (ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString String
s)
where
force :: [a] -> IO ()
force :: [a] -> IO ()
force = () -> IO ()
forall a. a -> IO a
evaluate (() -> IO ()) -> ([a] -> ()) -> [a] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> ()
forall a. [a] -> ()
seqList
seqList :: [a] -> ()
seqList :: [a] -> ()
seqList [] = ()
seqList (x :: a
x:xs :: [a]
xs) = a
x a -> () -> ()
forall a b. a -> b -> b
`seq` [a] -> ()
forall a. [a] -> ()
seqList [a]
xs
putLine :: Terminal -> String -> IO ()
putLine tm :: Terminal
tm s :: String
s = Terminal -> String -> IO ()
putPart Terminal
tm (String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ "\n")
putTemp :: Terminal -> String -> IO ()
putTemp tm :: Terminal
tm@(MkTerminal _ tmp :: IORef Int
tmp _ err :: String -> IO ()
err) s :: String
s =
do Int
n <- IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef IORef Int
tmp
String -> IO ()
err (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n '\b' String -> ShowS
forall a. [a] -> [a] -> [a]
++
String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ [ '\b' | Char
_ <- String
s ]
IORef Int -> Int -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Int
tmp (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s)