#!/usr/bin/env stack
> --stack --install-ghc runghc

This is a command-line Pomodoro counter.

> module Pomodoro (session, countdown) where

> import Control.Concurrent (threadDelay)
> import System.Console.ANSI (clearLine,
>                             saveCursor,
>                             restoreCursor)
> import System.IO (hFlush,
>                   stdout)
> import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
> import Data.Time.Format (formatTime, defaultTimeLocale)
>  
> data Pomodoro = First | Second | Third | Fourth
>     deriving (Pomodoro -> Pomodoro -> Bool
(Pomodoro -> Pomodoro -> Bool)
-> (Pomodoro -> Pomodoro -> Bool) -> Eq Pomodoro
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Pomodoro -> Pomodoro -> Bool
$c/= :: Pomodoro -> Pomodoro -> Bool
== :: Pomodoro -> Pomodoro -> Bool
$c== :: Pomodoro -> Pomodoro -> Bool
Eq, Eq Pomodoro
Eq Pomodoro
-> (Pomodoro -> Pomodoro -> Ordering)
-> (Pomodoro -> Pomodoro -> Bool)
-> (Pomodoro -> Pomodoro -> Bool)
-> (Pomodoro -> Pomodoro -> Bool)
-> (Pomodoro -> Pomodoro -> Bool)
-> (Pomodoro -> Pomodoro -> Pomodoro)
-> (Pomodoro -> Pomodoro -> Pomodoro)
-> Ord Pomodoro
Pomodoro -> Pomodoro -> Bool
Pomodoro -> Pomodoro -> Ordering
Pomodoro -> Pomodoro -> Pomodoro
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Pomodoro -> Pomodoro -> Pomodoro
$cmin :: Pomodoro -> Pomodoro -> Pomodoro
max :: Pomodoro -> Pomodoro -> Pomodoro
$cmax :: Pomodoro -> Pomodoro -> Pomodoro
>= :: Pomodoro -> Pomodoro -> Bool
$c>= :: Pomodoro -> Pomodoro -> Bool
> :: Pomodoro -> Pomodoro -> Bool
$c> :: Pomodoro -> Pomodoro -> Bool
<= :: Pomodoro -> Pomodoro -> Bool
$c<= :: Pomodoro -> Pomodoro -> Bool
< :: Pomodoro -> Pomodoro -> Bool
$c< :: Pomodoro -> Pomodoro -> Bool
compare :: Pomodoro -> Pomodoro -> Ordering
$ccompare :: Pomodoro -> Pomodoro -> Ordering
$cp1Ord :: Eq Pomodoro
Ord, Int -> Pomodoro -> ShowS
[Pomodoro] -> ShowS
Pomodoro -> String
(Int -> Pomodoro -> ShowS)
-> (Pomodoro -> String) -> ([Pomodoro] -> ShowS) -> Show Pomodoro
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pomodoro] -> ShowS
$cshowList :: [Pomodoro] -> ShowS
show :: Pomodoro -> String
$cshow :: Pomodoro -> String
showsPrec :: Int -> Pomodoro -> ShowS
$cshowsPrec :: Int -> Pomodoro -> ShowS
Show, ReadPrec [Pomodoro]
ReadPrec Pomodoro
Int -> ReadS Pomodoro
ReadS [Pomodoro]
(Int -> ReadS Pomodoro)
-> ReadS [Pomodoro]
-> ReadPrec Pomodoro
-> ReadPrec [Pomodoro]
-> Read Pomodoro
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Pomodoro]
$creadListPrec :: ReadPrec [Pomodoro]
readPrec :: ReadPrec Pomodoro
$creadPrec :: ReadPrec Pomodoro
readList :: ReadS [Pomodoro]
$creadList :: ReadS [Pomodoro]
readsPrec :: Int -> ReadS Pomodoro
$creadsPrec :: Int -> ReadS Pomodoro
Read, Pomodoro
Pomodoro -> Pomodoro -> Bounded Pomodoro
forall a. a -> a -> Bounded a
maxBound :: Pomodoro
$cmaxBound :: Pomodoro
minBound :: Pomodoro
$cminBound :: Pomodoro
Bounded, Int -> Pomodoro
Pomodoro -> Int
Pomodoro -> [Pomodoro]
Pomodoro -> Pomodoro
Pomodoro -> Pomodoro -> [Pomodoro]
Pomodoro -> Pomodoro -> Pomodoro -> [Pomodoro]
(Pomodoro -> Pomodoro)
-> (Pomodoro -> Pomodoro)
-> (Int -> Pomodoro)
-> (Pomodoro -> Int)
-> (Pomodoro -> [Pomodoro])
-> (Pomodoro -> Pomodoro -> [Pomodoro])
-> (Pomodoro -> Pomodoro -> [Pomodoro])
-> (Pomodoro -> Pomodoro -> Pomodoro -> [Pomodoro])
-> Enum Pomodoro
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Pomodoro -> Pomodoro -> Pomodoro -> [Pomodoro]
$cenumFromThenTo :: Pomodoro -> Pomodoro -> Pomodoro -> [Pomodoro]
enumFromTo :: Pomodoro -> Pomodoro -> [Pomodoro]
$cenumFromTo :: Pomodoro -> Pomodoro -> [Pomodoro]
enumFromThen :: Pomodoro -> Pomodoro -> [Pomodoro]
$cenumFromThen :: Pomodoro -> Pomodoro -> [Pomodoro]
enumFrom :: Pomodoro -> [Pomodoro]
$cenumFrom :: Pomodoro -> [Pomodoro]
fromEnum :: Pomodoro -> Int
$cfromEnum :: Pomodoro -> Int
toEnum :: Int -> Pomodoro
$ctoEnum :: Int -> Pomodoro
pred :: Pomodoro -> Pomodoro
$cpred :: Pomodoro -> Pomodoro
succ :: Pomodoro -> Pomodoro
$csucc :: Pomodoro -> Pomodoro
Enum)

> {-| Given an integer number of seconds, secToTimestamp
>  returns the corresponding time in MM:SS.
> 
> >>> secToTimestamp 0
> "00:00"
> >>> secToTimestamp 1500
> "25:00"
> >>> secToTimestamp 3000
> "50:00"
> -}
> 
> secToTimestamp :: Int -> String
> secToTimestamp :: Int -> String
secToTimestamp = TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%M:%S" (UTCTime -> String) -> (Int -> UTCTime) -> Int -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime) -> (Int -> POSIXTime) -> Int -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> POSIXTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral

> -- | Manage Pomodoro sessions
> -- 
> -- Examples:
> --
> -- >>> putStrLn "Hello world!"
> -- Hello world!
> --
> -- >>> putStrLn "Test complete!"
> -- Test complete!

> countdown :: IO()
> countdown :: IO ()
countdown = do
>     Int -> IO ()
wait_seconds (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
25 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
60 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

> -- | Replace a delay with no delay for testing purposes.
> no_del :: Int -> IO()
> no_del :: Int -> IO ()
no_del Int
_ = do
>     () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
 
> pom :: Show a => a -> IO ()
> pom :: a -> IO ()
pom a
m = do
>     String -> IO ()
putStr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ a -> String
forall a. Show a => a -> String
show a
m String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" pomodoro" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" | "
>     IO ()
saveCursor
>     Int -> IO ()
wait_seconds (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
25 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
60 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
>     IO ()
restoreCursor
>     String -> IO ()
putStrLn String
"Finished, take a 5 minute rest."

> to_work :: IO ()
> to_work :: IO ()
to_work = do
>     IO ()
saveCursor
>     String -> IO ()
putStr String
"Get back to work"
>     Int -> IO ()
delay Int
2
>     IO ()
restoreCursor
>     IO ()
clearLine

> pomodoro :: Pomodoro -> IO ()
> pomodoro :: Pomodoro -> IO ()
pomodoro Pomodoro
Fourth = do
>     Pomodoro -> IO ()
forall a. Show a => a -> IO ()
pom Pomodoro
Fourth
>     String -> IO ()
putStrLn String
"Take a 30-minute rest now. You just completed 4 pomodoros."
>     String -> IO ()
putStrLn String
"Congratulations on 4 pomodoros finished in a row!"
> pomodoro Pomodoro
m = do
>     Pomodoro -> IO ()
forall a. Show a => a -> IO ()
pom Pomodoro
m
>     Int -> IO ()
delay (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
5 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
60
>     IO ()
to_work
>     Pomodoro -> IO ()
pomodoro (Pomodoro -> IO ()) -> Pomodoro -> IO ()
forall a b. (a -> b) -> a -> b
$ Pomodoro -> Pomodoro
forall a. Enum a => a -> a
succ Pomodoro
m
>  
> wait_seconds :: Int -> IO()
> wait_seconds :: Int -> IO ()
wait_seconds Int
0 = String -> IO ()
putStr String
""
> wait_seconds Int
n = do
>     IO ()
saveCursor
>     String -> IO ()
putStr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ Int -> String
secToTimestamp (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
>     Handle -> IO ()
hFlush Handle
stdout
>     IO ()
restoreCursor
>     Int -> IO ()
delay Int
1
>     Int -> IO ()
wait_seconds (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

> -- | delay: Pauses the thread for the given number of seconds.
> --
> -- Example:
> --
> -- >>> delay 0

> delay :: Int -> IO()
> delay :: Int -> IO ()
delay Int
n = Int -> IO ()
threadDelay (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000

> session :: IO()
> session :: IO ()
session = Pomodoro -> IO ()
pomodoro Pomodoro
First

> main :: IO()
> main :: IO ()
main = IO ()
session