some beautiful error messages
[laziness.git] / laziness.hs
blob683531ca142d0e2640ecc26f8b1a6edd78b86cda
1 {-
2 - laziness: a tool to memoize your Earth-seizure plans
3 - by Sergey 'L29Ah' Alirzaev, <zl29ah@gmail.com>
5 - File format:
6 - <id>\t<description>\t<importance>\t<start timestamp>\t<end timestamp>
7 - [\t<dependency>[\t<dependency>...]]\n<id>\t...
8 -}
10 import qualified Data.Map as M
11 import Data.List.Split
12 import Data.Maybe
13 import Data.DateTime
15 import Control.Monad
17 import System
19 data Todo = Todo {
20 descr :: String,
21 deps :: [String], -- deps also can be used as anti-tags
22 importance :: Integer,
23 timeStart :: Integer,
24 timeEnd :: Integer
25 } deriving (Show, Eq)
27 instance Ord Todo where
28 compare x y = compare (importance x) (importance y)
30 parseLine :: String -> Maybe (String, Todo)
31 parseLine line | null line = Nothing
32 | otherwise = Just $
33 (\(key:descr:imp:ts:te:deps) -> (key, Todo descr deps (read imp) (read ts) (read te))) $ sepBy "\t" line
35 prettyTodo :: Todo -> String
36 prettyTodo (Todo descr deps imp ts te) = "\27[" ++ (
37 if imp > 100 then "31" else -- Nice coloring
38 if imp > 10 then "33" else
39 if imp > -10 then "37" else
40 if imp > -100 then "36" else "34") ++ "m" ++ descr ++ d ts ++ d te ++ "\n"
41 where d x = if x == 0 then "" else " - " ++ prettyDate x
43 prettyDate :: Integer -> String
44 prettyDate = show . fromSeconds
46 prettyLine :: Int -> Todo -> String
47 prettyLine depth x = "\27[37m" ++ padding ++ prettyTodo x
48 where padding = concat $ replicate depth "| "
50 pretty :: [(Int, Todo)] -> String
51 pretty = concatMap (uncurry prettyLine)
53 dig :: M.Map String Todo -> String -> Int -> String
54 dig db id maxdepth = pretty $ _dig db id 0 maxdepth
56 _dig :: M.Map String Todo -> String -> Int -> Int -> [(Int, Todo)]
57 _dig _ _ _ 0 = []
58 _dig db id curdepth maxdepth = (curdepth, node) :
59 (concatMap (\x -> _dig db x (curdepth + 1) (maxdepth - 1)) $ deps node)
60 where node = fromMaybe (error $ "No node named \"" ++ id ++ "\" in the database!") $ M.lookup id db
62 -- TODO: use getOpt
63 main = do
64 args <- getArgs
65 when (length args == 0) $ error usage
66 let (action:cmdargs) = args
67 f <- readFile ".todo"
68 let db = M.fromList $ catMaybes $ map parseLine $ lines f
69 putStr $ case action of
70 "dig" -> dig db (cmdargs!!0) (read $ cmdargs!!1)
71 otherwise -> error usage
73 usage = "Usage:\n" ++
74 "laziness dig <id> <depth> -- make laziness print todo graph starting at 'id' up to 'depth' jumps into\n"