Monadoro 0.3.0.0 → 0.3.1.0
raw patch · 5 files changed
+150/−125 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ CLI: containsEither :: Eq a => [a] -> [a] -> Bool
+ CLI: filterParams :: [String] -> [String]
+ CLI: printVersion :: IO ()
+ CLI: runPomodoros :: [String] -> IO ()
+ CLI: runSession :: [String] -> IO ()
+ CLI: showManual :: IO ()
+ CLI: showUsage :: IO ()
Files
- Monadoro.cabal +2/−1
- app/Main.hs +13/−123
- changelog +4/−0
- src/CLI.hs +130/−0
- test/DocTests.hs +1/−1
Monadoro.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: Monadoro-version: 0.3.0.0+version: 0.3.1.0 synopsis: A minimalistic CLI Pomodoro timer. description: A Pomodoro timer with two modes: single-pomodoro (default), and four-pomodoro (`--session`). category: Tools@@ -26,6 +26,7 @@ library exposed-modules:+ CLI ConsoleDisplay CountdownLoop ParseTime
app/Main.hs view
@@ -1,132 +1,22 @@ module Main where -import Control.Monad (void)-import Data.Char (isDigit)-import Data.List (intersect)-import Data.Version (showVersion) import System.Environment (getArgs)-import System.Exit (ExitCode(ExitSuccess))-import Control.Concurrent (threadDelay)-import System.Process (system)+import CLI (containsEither,+ filterParams,+ printVersion,+ runPomodoros,+ runSession,+ showManual,+ showUsage) -import CountdownLoop (countdown_loop)-import Pomodoro (session) -import Paths_Monadoro (getDataFileName, version)- main :: IO ()-main = monadoro--monadoro :: IO ()-monadoro = getArgs >>= parseArgs--remove :: String -> [String] -> [String]-remove element list = filter (/=element) list+main = getArgs >>= parseArgs parseArgs :: [String] -> IO () parseArgs xs- | xs `containsEither` ["--help", "-h"] = putStrLn usage- | xs `containsEither` ["--version", "-v"] = putStrLn . showVersion $ version- | xs `containsEither` ["--session", "-s"] = session (getDelayIfNeeded xs)- | xs `containsEither` ["--man", "-m"] = do- man_file <- getDataFileName "man/monadoro.1"- ExitSuccess <- system $ "man " ++ man_file- return ()- | otherwise = do- let filtered_params = filterParams xs- runPomodoro (getDelayIfNeeded xs) filtered_params--filterParams :: [String] -> [String]-filterParams xs = (remove "-n" . remove "--nodelay") xs--runPomodoro :: IO () -> [String] -> IO ()-runPomodoro delay xs = do- warnAboutErrorsIfAny invalidIntervals- runTimer delay validIntervals- where (validIntervals, invalidIntervals) = checkInput xs--with_delay :: IO()-with_delay = wait 1---- Mocks a delay for test purposes.-no_delay :: IO()-no_delay = wait 0--getDelayIfNeeded :: [String] -> IO ()-getDelayIfNeeded xs- | xs `containsEither` ["--nodelay", "-n"] = no_delay- | otherwise = with_delay--warnAboutErrorsIfAny :: [String] -> IO ()-warnAboutErrorsIfAny [] = return ()-warnAboutErrorsIfAny errors =- putStrLn $ "Unable to parse as interval: " ++ show errors--{-| checkInput--Returns valid entries (first list) and invalid entries (second list).-->>> checkInput []-([],[])-->>> checkInput ["x"]-([],["x"])-->>> checkInput ["00:00"]-(["00:00"],[])-->>> checkInput ["00:00", "x"]-(["00:00"],["x"])-->>> checkInput ["00:00", "x"]-(["00:00"],["x"])-->>> checkInput ["00:00", "00:01", "x"]-(["00:00","00:01"],["x"])---}--checkInput :: [String] -> ([String], [String])-checkInput [] = ([], [])-checkInput [x]- | isValidTimeInterval x = ([x], [])- | otherwise = ([], [x])-checkInput (x:xs) = (validEntries, invalidEntries)- where- validEntries =- fst (checkInput [x]) ++ fst (checkInput xs)- invalidEntries =- snd (checkInput [x]) ++ snd (checkInput xs)--{-| isValidTimeInterval-->>> isValidTimeInterval "x"-False-->>> isValidTimeInterval "00:00"-True---}--isValidTimeInterval :: String -> Bool-isValidTimeInterval (m1:m2:':':s1:[s2])- | all isDigit [m1, m2, s1, s2] = True-isValidTimeInterval _ = False--containsEither :: (Eq a) => [a] -> [a] -> Bool-containsEither a = not . null . intersect a--usage :: String-usage = "Usage: monadoro [-h|--help] [-m|--man] [-v|--version] [--session]" ++- "[INTERVAL [...]]"--milisec_per_second :: Int-milisec_per_second = 10 ^ (6 :: Int)--wait :: Int -> IO()-wait n = threadDelay (n * milisec_per_second)--runTimer :: IO () -> [String] -> IO ()-runTimer delayer [] = void (countdown_loop delayer "25:00")-runTimer delayer [t] = void (countdown_loop delayer t)-runTimer delayer (t:ts) = parseArgs [t] >> parseArgs ts+ | xs `containsEither` ["--help", "-h"] = showUsage+ | xs `containsEither` ["--version", "-v"] = printVersion+ | xs `containsEither` ["--session", "-s"] = runSession xs+ | xs `containsEither` ["--man", "-m"] = showManual+ | otherwise = runPomodoros xs
changelog view
@@ -1,3 +1,7 @@+monadoro (3.1.0)++ * Move library functions out of the main module.+ monadoro (3.0.0) * Drop dependency on package ansi-terminal.
+ src/CLI.hs view
@@ -0,0 +1,130 @@+module CLI (+ containsEither,+ filterParams,+ printVersion,+ runPomodoros,+ runSession,+ showManual,+ showUsage+) where++import Control.Concurrent (threadDelay)+import Control.Monad (void)+import Data.Char (isDigit)+import Data.List (intersect)+import Data.Version (showVersion)+import System.Exit (ExitCode(ExitSuccess))+import System.Process (system)++import Paths_Monadoro (getDataFileName, version)+import CountdownLoop (countdown_loop)+import Pomodoro (session)++showUsage :: IO ()+showUsage = putStrLn usage++usage :: String+usage = "Usage: monadoro [-h|--help] [-m|--man] [-v|--version] [--session]" +++ "[INTERVAL [...]]"++runPomodoros :: [String] -> IO ()+runPomodoros xs = runPomodoro $ filterParams xs++runPomodoro :: [String] -> IO ()+runPomodoro xs = do+ warnAboutErrorsIfAny invalidIntervals+ runTimer (getDelayIfNeeded xs) validIntervals+ where (validIntervals, invalidIntervals) = checkInput xs++runSession :: [String] -> IO ()+runSession xs = session (getDelayIfNeeded xs)++runTimer :: IO () -> [String] -> IO ()+runTimer delayer [] = void (countdown_loop delayer "25:00")+runTimer delayer [t] = void (countdown_loop delayer t)+runTimer delayer (t:ts) = runTimer delayer [t] >> runTimer delayer ts++filterParams :: [String] -> [String]+filterParams xs = (remove "-n" . remove "--nodelay") xs++remove :: String -> [String] -> [String]+remove element list = filter (/=element) list++showManual :: IO ()+showManual = do+ man_file <- getDataFileName "man/monadoro.1"+ ExitSuccess <- system $ "man " ++ man_file+ return ()++printVersion :: IO ()+printVersion = putStrLn . showVersion $ version++warnAboutErrorsIfAny :: [String] -> IO ()+warnAboutErrorsIfAny [] = return ()+warnAboutErrorsIfAny errors =+ putStrLn $ "Unable to parse as interval: " ++ show errors++{-| checkInput++Returns valid entries (first list) and invalid entries (second list).++>>> checkInput []+([],[])++>>> checkInput ["x"]+([],["x"])++>>> checkInput ["00:00"]+(["00:00"],[])++>>> checkInput ["00:00", "x"]+(["00:00"],["x"])++>>> checkInput ["00:00", "x"]+(["00:00"],["x"])++>>> checkInput ["00:00", "00:01", "x"]+(["00:00","00:01"],["x"])++-}++checkInput :: [String] -> ([String], [String])+checkInput [] = ([], [])+checkInput [x]+ | isValidTimeInterval x = ([x], [])+ | otherwise = ([], [x])+checkInput (x:xs) = (validEntries, invalidEntries)+ where+ validEntries =+ fst (checkInput [x]) ++ fst (checkInput xs)+ invalidEntries =+ snd (checkInput [x]) ++ snd (checkInput xs)++{-| isValidTimeInterval++>>> isValidTimeInterval "x"+False++>>> isValidTimeInterval "00:00"+True++-}++isValidTimeInterval :: String -> Bool+isValidTimeInterval (m1:m2:':':s1:[s2])+ | all isDigit [m1, m2, s1, s2] = True+isValidTimeInterval _ = False++containsEither :: (Eq a) => [a] -> [a] -> Bool+containsEither a = not . null . intersect a++getDelayIfNeeded :: [String] -> IO ()+getDelayIfNeeded xs+ | xs `containsEither` ["--nodelay", "-n"] = wait 0+ | otherwise = wait 1++milisec_per_second :: Int+milisec_per_second = 10 ^ (6 :: Int)++wait :: Int -> IO()+wait n = threadDelay (n * milisec_per_second)
test/DocTests.hs view
@@ -5,7 +5,7 @@ main :: IO () main = doctest [ "-isrc",- "app/Main.hs",+ "src/CLI.hs", "src/ParseTime.lhs", "src/CountdownLoop.hs", "src/Pomodoro.lhs",