{-# LANGUAGE CPP #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE ScopedTypeVariables #-}
module XMonad.Prompt.OrgMode (
orgPrompt,
orgPromptPrimary,
ClipboardSupport (..),
OrgMode,
#ifdef TESTING
pInput,
Note (..),
Date (..),
Time (..),
TimeOfDay (..),
DayOfWeek (..),
#endif
) where
import XMonad.Prelude
import XMonad (X, io)
import XMonad.Prompt (XPConfig, XPrompt (showXPrompt), mkXPrompt)
import XMonad.Util.Parser
import XMonad.Util.XSelection (getSelection)
import Data.Time (Day (ModifiedJulianDay), NominalDiffTime, UTCTime (utctDay), addUTCTime, defaultTimeLocale, formatTime, fromGregorian, getCurrentTime, iso8601DateFormat, nominalDay, toGregorian)
import System.IO (IOMode (AppendMode), hPutStrLn, withFile)
data OrgMode = OrgMode
{ OrgMode -> ClipboardSupport
clpSupport :: ClipboardSupport
, :: String
, OrgMode -> String
orgFile :: FilePath
}
data ClipboardSupport
= PrimarySelection
| NoClpSupport
data Clp
= String
| Body String
instance XPrompt OrgMode where
showXPrompt :: OrgMode -> String
showXPrompt :: OrgMode -> String
showXPrompt OrgMode{ String
todoHeader :: String
todoHeader :: OrgMode -> String
todoHeader, String
orgFile :: String
orgFile :: OrgMode -> String
orgFile, ClipboardSupport
clpSupport :: ClipboardSupport
clpSupport :: OrgMode -> ClipboardSupport
clpSupport } =
[String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"Add ", String
todoHeader, String
clp, String
" to ", String
orgFile, String
": "]
where
String
clp :: String = case ClipboardSupport
clpSupport of
ClipboardSupport
NoClpSupport -> String
""
ClipboardSupport
PrimarySelection -> String
" + PS"
orgPrompt
:: XPConfig
-> String
-> FilePath
-> X ()
orgPrompt :: XPConfig -> String -> String -> X ()
orgPrompt XPConfig
xpc = XPConfig -> OrgMode -> X ()
mkOrgPrompt XPConfig
xpc (OrgMode -> X ())
-> (String -> String -> OrgMode) -> String -> String -> X ()
forall a b c d. (a -> b) -> (c -> d -> a) -> c -> d -> b
.: ClipboardSupport -> String -> String -> OrgMode
OrgMode ClipboardSupport
NoClpSupport
orgPromptPrimary :: XPConfig -> String -> FilePath -> X ()
orgPromptPrimary :: XPConfig -> String -> String -> X ()
orgPromptPrimary XPConfig
xpc = XPConfig -> OrgMode -> X ()
mkOrgPrompt XPConfig
xpc (OrgMode -> X ())
-> (String -> String -> OrgMode) -> String -> String -> X ()
forall a b c d. (a -> b) -> (c -> d -> a) -> c -> d -> b
.: ClipboardSupport -> String -> String -> OrgMode
OrgMode ClipboardSupport
PrimarySelection
mkOrgPrompt :: XPConfig -> OrgMode -> X ()
mkOrgPrompt :: XPConfig -> OrgMode -> X ()
mkOrgPrompt XPConfig
xpc oc :: OrgMode
oc@OrgMode{ String
todoHeader :: String
todoHeader :: OrgMode -> String
todoHeader, String
orgFile :: String
orgFile :: OrgMode -> String
orgFile, ClipboardSupport
clpSupport :: ClipboardSupport
clpSupport :: OrgMode -> ClipboardSupport
clpSupport } =
OrgMode -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
forall p.
XPrompt p =>
p -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
mkXPrompt OrgMode
oc XPConfig
xpc (IO [String] -> ComplFunction
forall a b. a -> b -> a
const ([String] -> IO [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [])) String -> X ()
appendNote
where
appendNote :: String -> X ()
appendNote :: String -> X ()
appendNote String
input = IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ do
Clp
clpStr <- case ClipboardSupport
clpSupport of
ClipboardSupport
NoClpSupport -> Clp -> IO Clp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Clp -> IO Clp) -> Clp -> IO Clp
forall a b. (a -> b) -> a -> b
$ String -> Clp
Body String
""
ClipboardSupport
PrimarySelection -> do
String
sel <- IO String
forall (m :: * -> *). MonadIO m => m String
getSelection
Clp -> IO Clp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Clp -> IO Clp) -> Clp -> IO Clp
forall a b. (a -> b) -> a -> b
$ if (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
sel) [String
"http://", String
"https://"]
then String -> Clp
Header String
sel
else String -> Clp
Body (String -> Clp) -> String -> Clp
forall a b. (a -> b) -> a -> b
$ String
"\n " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
sel
String
fp <- String -> IO String
forall (m :: * -> *). MonadIO m => String -> m String
mkAbsolutePath String
orgFile
String -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
fp IOMode
AppendMode ((Handle -> IO ()) -> IO ())
-> (String -> Handle -> IO ()) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> String -> IO ()) -> String -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> String -> IO ()
hPutStrLn
(String -> IO ()) -> (String -> IO String) -> String -> IO ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< IO String -> (Note -> IO String) -> Maybe Note -> IO String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
"") (Clp -> String -> Note -> IO String
ppNote Clp
clpStr String
todoHeader) (Maybe Note -> IO String)
-> (String -> Maybe Note) -> String -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe Note
pInput
(String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
input
data Time = Time
{ Time -> Date
date :: Date
, Time -> Maybe TimeOfDay
tod :: Maybe TimeOfDay
}
deriving (Time -> Time -> Bool
(Time -> Time -> Bool) -> (Time -> Time -> Bool) -> Eq Time
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Time -> Time -> Bool
$c/= :: Time -> Time -> Bool
== :: Time -> Time -> Bool
$c== :: Time -> Time -> Bool
Eq, Int -> Time -> String -> String
[Time] -> String -> String
Time -> String
(Int -> Time -> String -> String)
-> (Time -> String) -> ([Time] -> String -> String) -> Show Time
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [Time] -> String -> String
$cshowList :: [Time] -> String -> String
show :: Time -> String
$cshow :: Time -> String
showsPrec :: Int -> Time -> String -> String
$cshowsPrec :: Int -> Time -> String -> String
Show)
data TimeOfDay = TimeOfDay Int Int
deriving (TimeOfDay -> TimeOfDay -> Bool
(TimeOfDay -> TimeOfDay -> Bool)
-> (TimeOfDay -> TimeOfDay -> Bool) -> Eq TimeOfDay
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TimeOfDay -> TimeOfDay -> Bool
$c/= :: TimeOfDay -> TimeOfDay -> Bool
== :: TimeOfDay -> TimeOfDay -> Bool
$c== :: TimeOfDay -> TimeOfDay -> Bool
Eq)
instance Show TimeOfDay where
show :: TimeOfDay -> String
show :: TimeOfDay -> String
show (TimeOfDay Int
h Int
m) = Int -> String
pad Int
h String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
":" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
pad Int
m
where
pad :: Int -> String
pad :: Int -> String
pad Int
n = (if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
9 then String
"0" else String
"") String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
n
data Date
= Today
| Tomorrow
| Next DayOfWeek
| Date (Int, Maybe Int, Maybe Integer)
deriving (Date -> Date -> Bool
(Date -> Date -> Bool) -> (Date -> Date -> Bool) -> Eq Date
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Date -> Date -> Bool
$c/= :: Date -> Date -> Bool
== :: Date -> Date -> Bool
$c== :: Date -> Date -> Bool
Eq, Eq Date
Eq Date
-> (Date -> Date -> Ordering)
-> (Date -> Date -> Bool)
-> (Date -> Date -> Bool)
-> (Date -> Date -> Bool)
-> (Date -> Date -> Bool)
-> (Date -> Date -> Date)
-> (Date -> Date -> Date)
-> Ord Date
Date -> Date -> Bool
Date -> Date -> Ordering
Date -> Date -> Date
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 :: Date -> Date -> Date
$cmin :: Date -> Date -> Date
max :: Date -> Date -> Date
$cmax :: Date -> Date -> Date
>= :: Date -> Date -> Bool
$c>= :: Date -> Date -> Bool
> :: Date -> Date -> Bool
$c> :: Date -> Date -> Bool
<= :: Date -> Date -> Bool
$c<= :: Date -> Date -> Bool
< :: Date -> Date -> Bool
$c< :: Date -> Date -> Bool
compare :: Date -> Date -> Ordering
$ccompare :: Date -> Date -> Ordering
Ord, Int -> Date -> String -> String
[Date] -> String -> String
Date -> String
(Int -> Date -> String -> String)
-> (Date -> String) -> ([Date] -> String -> String) -> Show Date
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [Date] -> String -> String
$cshowList :: [Date] -> String -> String
show :: Date -> String
$cshow :: Date -> String
showsPrec :: Int -> Date -> String -> String
$cshowsPrec :: Int -> Date -> String -> String
Show)
toOrgFmt :: Maybe TimeOfDay -> Day -> String
toOrgFmt :: Maybe TimeOfDay -> Day -> String
toOrgFmt Maybe TimeOfDay
tod Day
day =
[String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"<", String
isoDay, String
" ", Int -> String -> String
forall a. Int -> [a] -> [a]
take Int
3 (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ DayOfWeek -> String
forall a. Show a => a -> String
show (Day -> DayOfWeek
dayOfWeek Day
day), String
time, String
">"]
where
String
time :: String = String -> (TimeOfDay -> String) -> Maybe TimeOfDay -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" ((Char
' ' Char -> String -> String
forall a. a -> [a] -> [a]
:) (String -> String) -> (TimeOfDay -> String) -> TimeOfDay -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeOfDay -> String
forall a. Show a => a -> String
show) Maybe TimeOfDay
tod
String
isoDay :: String = TimeLocale -> String -> Day -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale (Maybe String -> String
iso8601DateFormat Maybe String
forall a. Maybe a
Nothing) Day
day
ppDate :: Time -> IO String
ppDate :: Time -> IO String
ppDate Time{ Date
date :: Date
date :: Time -> Date
date, Maybe TimeOfDay
tod :: Maybe TimeOfDay
tod :: Time -> Maybe TimeOfDay
tod } = do
UTCTime
curTime <- IO UTCTime
getCurrentTime
let curDay :: Day
curDay = UTCTime -> Day
utctDay UTCTime
curTime
(Integer
y, Int
m, Int
_) = Day -> (Integer, Int, Int)
toGregorian Day
curDay
diffToDay :: DayOfWeek -> NominalDiffTime
diffToDay DayOfWeek
d = DayOfWeek -> DayOfWeek -> NominalDiffTime
diffBetween DayOfWeek
d (Day -> DayOfWeek
dayOfWeek Day
curDay)
String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> (Day -> String) -> Day -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe TimeOfDay -> Day -> String
toOrgFmt Maybe TimeOfDay
tod (Day -> IO String) -> Day -> IO String
forall a b. (a -> b) -> a -> b
$ case Date
date of
Date
Today -> Day
curDay
Date
Tomorrow -> UTCTime -> Day
utctDay (UTCTime -> Day) -> UTCTime -> Day
forall a b. (a -> b) -> a -> b
$ NominalDiffTime -> UTCTime -> UTCTime
addDays NominalDiffTime
1 UTCTime
curTime
Next DayOfWeek
wday -> UTCTime -> Day
utctDay (UTCTime -> Day) -> UTCTime -> Day
forall a b. (a -> b) -> a -> b
$ NominalDiffTime -> UTCTime -> UTCTime
addDays (DayOfWeek -> NominalDiffTime
diffToDay DayOfWeek
wday) UTCTime
curTime
Date (Int
d, Maybe Int
mbM, Maybe Integer
mbY) -> Integer -> Int -> Int -> Day
fromGregorian (Integer -> Maybe Integer -> Integer
forall a. a -> Maybe a -> a
fromMaybe Integer
y Maybe Integer
mbY) (Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
m Maybe Int
mbM) Int
d
where
NominalDiffTime -> UTCTime -> UTCTime
addDays :: NominalDiffTime -> UTCTime -> UTCTime
= NominalDiffTime -> UTCTime -> UTCTime
addUTCTime (NominalDiffTime -> UTCTime -> UTCTime)
-> (NominalDiffTime -> NominalDiffTime)
-> NominalDiffTime
-> UTCTime
-> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
* NominalDiffTime
nominalDay)
diffBetween :: DayOfWeek -> DayOfWeek -> NominalDiffTime
diffBetween :: DayOfWeek -> DayOfWeek -> NominalDiffTime
diffBetween DayOfWeek
d DayOfWeek
cur
| DayOfWeek
d DayOfWeek -> DayOfWeek -> Bool
forall a. Eq a => a -> a -> Bool
== DayOfWeek
cur = NominalDiffTime
7
| Bool
otherwise = Int -> NominalDiffTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> NominalDiffTime) -> (Int -> Int) -> Int -> NominalDiffTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a. Num a => a -> a
abs (Int -> NominalDiffTime) -> Int -> NominalDiffTime
forall a b. (a -> b) -> a -> b
$ (DayOfWeek -> Int
forall a. Enum a => a -> Int
fromEnum DayOfWeek
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- DayOfWeek -> Int
forall a. Enum a => a -> Int
fromEnum DayOfWeek
cur) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
7
dayOfWeek :: Day -> DayOfWeek
dayOfWeek :: Day -> DayOfWeek
dayOfWeek (ModifiedJulianDay Integer
d) = Int -> DayOfWeek
forall a. Enum a => Int -> a
toEnum (Int -> DayOfWeek) -> Int -> DayOfWeek
forall a b. (a -> b) -> a -> b
$ Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Integer
d Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
3
data DayOfWeek
= Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
deriving (DayOfWeek -> DayOfWeek -> Bool
(DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool) -> Eq DayOfWeek
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DayOfWeek -> DayOfWeek -> Bool
$c/= :: DayOfWeek -> DayOfWeek -> Bool
== :: DayOfWeek -> DayOfWeek -> Bool
$c== :: DayOfWeek -> DayOfWeek -> Bool
Eq, Eq DayOfWeek
Eq DayOfWeek
-> (DayOfWeek -> DayOfWeek -> Ordering)
-> (DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> DayOfWeek)
-> (DayOfWeek -> DayOfWeek -> DayOfWeek)
-> Ord DayOfWeek
DayOfWeek -> DayOfWeek -> Bool
DayOfWeek -> DayOfWeek -> Ordering
DayOfWeek -> DayOfWeek -> DayOfWeek
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 :: DayOfWeek -> DayOfWeek -> DayOfWeek
$cmin :: DayOfWeek -> DayOfWeek -> DayOfWeek
max :: DayOfWeek -> DayOfWeek -> DayOfWeek
$cmax :: DayOfWeek -> DayOfWeek -> DayOfWeek
>= :: DayOfWeek -> DayOfWeek -> Bool
$c>= :: DayOfWeek -> DayOfWeek -> Bool
> :: DayOfWeek -> DayOfWeek -> Bool
$c> :: DayOfWeek -> DayOfWeek -> Bool
<= :: DayOfWeek -> DayOfWeek -> Bool
$c<= :: DayOfWeek -> DayOfWeek -> Bool
< :: DayOfWeek -> DayOfWeek -> Bool
$c< :: DayOfWeek -> DayOfWeek -> Bool
compare :: DayOfWeek -> DayOfWeek -> Ordering
$ccompare :: DayOfWeek -> DayOfWeek -> Ordering
Ord, Int -> DayOfWeek -> String -> String
[DayOfWeek] -> String -> String
DayOfWeek -> String
(Int -> DayOfWeek -> String -> String)
-> (DayOfWeek -> String)
-> ([DayOfWeek] -> String -> String)
-> Show DayOfWeek
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [DayOfWeek] -> String -> String
$cshowList :: [DayOfWeek] -> String -> String
show :: DayOfWeek -> String
$cshow :: DayOfWeek -> String
showsPrec :: Int -> DayOfWeek -> String -> String
$cshowsPrec :: Int -> DayOfWeek -> String -> String
Show)
instance Enum DayOfWeek where
toEnum :: Int -> DayOfWeek
toEnum :: Int -> DayOfWeek
toEnum Int
i = case Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod Int
i Int
7 of
Int
0 -> DayOfWeek
Sunday
Int
1 -> DayOfWeek
Monday
Int
2 -> DayOfWeek
Tuesday
Int
3 -> DayOfWeek
Wednesday
Int
4 -> DayOfWeek
Thursday
Int
5 -> DayOfWeek
Friday
Int
_ -> DayOfWeek
Saturday
fromEnum :: DayOfWeek -> Int
fromEnum :: DayOfWeek -> Int
fromEnum = \case
DayOfWeek
Monday -> Int
1
DayOfWeek
Tuesday -> Int
2
DayOfWeek
Wednesday -> Int
3
DayOfWeek
Thursday -> Int
4
DayOfWeek
Friday -> Int
5
DayOfWeek
Saturday -> Int
6
DayOfWeek
Sunday -> Int
7
data Note
= Scheduled String Time
| Deadline String Time
| NormalMsg String
deriving (Note -> Note -> Bool
(Note -> Note -> Bool) -> (Note -> Note -> Bool) -> Eq Note
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Note -> Note -> Bool
$c/= :: Note -> Note -> Bool
== :: Note -> Note -> Bool
$c== :: Note -> Note -> Bool
Eq, Int -> Note -> String -> String
[Note] -> String -> String
Note -> String
(Int -> Note -> String -> String)
-> (Note -> String) -> ([Note] -> String -> String) -> Show Note
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [Note] -> String -> String
$cshowList :: [Note] -> String -> String
show :: Note -> String
$cshow :: Note -> String
showsPrec :: Int -> Note -> String -> String
$cshowsPrec :: Int -> Note -> String -> String
Show)
ppNote :: Clp -> String -> Note -> IO String
ppNote :: Clp -> String -> Note -> IO String
ppNote Clp
clp String
todo = \case
Scheduled String
str Time
time -> String -> String -> Maybe Time -> IO String
mkLine String
str String
"SCHEDULED: " (Time -> Maybe Time
forall a. a -> Maybe a
Just Time
time)
Deadline String
str Time
time -> String -> String -> Maybe Time -> IO String
mkLine String
str String
"DEADLINE: " (Time -> Maybe Time
forall a. a -> Maybe a
Just Time
time)
NormalMsg String
str -> String -> String -> Maybe Time -> IO String
mkLine String
str String
"" Maybe Time
forall a. Maybe a
Nothing
where
mkLine :: String -> String -> Maybe Time -> IO String
mkLine :: String -> String -> Maybe Time -> IO String
mkLine String
str String
sched Maybe Time
time = do
String
t <- case Maybe Time
time of
Maybe Time
Nothing -> String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
""
Just Time
ti -> ((String
"\n " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
sched) String -> String -> String
forall a. Semigroup a => a -> a -> a
<>) (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Time -> IO String
ppDate Time
ti
String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ case Clp
clp of
Body String
c -> [String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"* ", String
todo, String
" ", String
str, String
t, String
c]
Header String
c -> [String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"* ", String
todo, String
" [[", String
c, String
"][", String
str,String
"]]", String
t]
pInput :: String -> Maybe Note
pInput :: String -> Maybe Note
pInput String
inp = (Parser Note -> String -> Maybe Note
forall a. Parser a -> String -> Maybe a
`runParser` String
inp) (Parser Note -> Maybe Note)
-> ([Parser Note] -> Parser Note) -> [Parser Note] -> Maybe Note
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Parser Note] -> Parser Note
forall a. [Parser a] -> Parser a
choice ([Parser Note] -> Maybe Note) -> [Parser Note] -> Maybe Note
forall a b. (a -> b) -> a -> b
$
[ String -> Time -> Note
Scheduled (String -> Time -> Note) -> Parser String -> Parser (Time -> Note)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Parser String
getLast String
"+s" Parser (Time -> Note) -> Parser Time -> Parser Note
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Date -> Maybe TimeOfDay -> Time
Time (Date -> Maybe TimeOfDay -> Time)
-> Parser Date -> Parser (Maybe TimeOfDay -> Time)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Date
pDate Parser (Maybe TimeOfDay -> Time)
-> Parser (Maybe TimeOfDay) -> Parser Time
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe TimeOfDay)
pTimeOfDay)
, String -> Time -> Note
Deadline (String -> Time -> Note) -> Parser String -> Parser (Time -> Note)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Parser String
getLast String
"+d" Parser (Time -> Note) -> Parser Time -> Parser Note
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Date -> Maybe TimeOfDay -> Time
Time (Date -> Maybe TimeOfDay -> Time)
-> Parser Date -> Parser (Maybe TimeOfDay -> Time)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Date
pDate Parser (Maybe TimeOfDay -> Time)
-> Parser (Maybe TimeOfDay) -> Parser Time
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe TimeOfDay)
pTimeOfDay)
, String -> Note
NormalMsg (String -> Note) -> Parser String -> Parser Note
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser String
munch1 (Bool -> Char -> Bool
forall a b. a -> b -> a
const Bool
True)
]
where
getLast :: String -> Parser String
getLast :: String -> Parser String
getLast String
ptn = String -> String
forall a. [a] -> [a]
reverse
(String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ')
(String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> String
forall a. Int -> [a] -> [a]
drop (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
ptn)
(String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
reverse
(String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
([String] -> String) -> Parser [String] -> Parser String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String -> Parser String -> Parser [String]
forall a sep. Parser a -> Parser sep -> Parser [a]
endBy1 (String -> Parser String
go String
"") (String -> Parser String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
ptn)
where
go :: String -> Parser String
go :: String -> Parser String
go String
consumed = do
String
str <- (Char -> Bool) -> Parser String
munch (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= String -> Char
forall a. [a] -> a
head String
ptn)
String
word <- (Char -> Bool) -> Parser String
munch1 (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' ')
(String -> Parser String)
-> (String -> Parser String) -> Bool -> String -> Parser String
forall a. a -> a -> Bool -> a
bool String -> Parser String
go String -> Parser String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String
word String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
ptn) (String -> Parser String) -> String -> Parser String
forall a b. (a -> b) -> a -> b
$ String
consumed String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
str String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
word
pTimeOfDay :: Parser (Maybe TimeOfDay)
pTimeOfDay :: Parser (Maybe TimeOfDay)
pTimeOfDay = [Parser (Maybe TimeOfDay)] -> Parser (Maybe TimeOfDay)
forall a. [Parser a] -> Parser a
choice
[ TimeOfDay -> Maybe TimeOfDay
forall a. a -> Maybe a
Just (TimeOfDay -> Maybe TimeOfDay)
-> Parser TimeOfDay -> Parser (Maybe TimeOfDay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int -> Int -> TimeOfDay
TimeOfDay (Int -> Int -> TimeOfDay)
-> Parser Int -> Parser (Int -> TimeOfDay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Int
pHour Parser (Int -> TimeOfDay)
-> Parser String -> Parser (Int -> TimeOfDay)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* String -> Parser String
string String
":" Parser (Int -> TimeOfDay) -> Parser Int -> Parser TimeOfDay
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Int
pMinute)
, TimeOfDay -> Maybe TimeOfDay
forall a. a -> Maybe a
Just (TimeOfDay -> Maybe TimeOfDay)
-> Parser TimeOfDay -> Parser (Maybe TimeOfDay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int -> Int -> TimeOfDay
TimeOfDay (Int -> Int -> TimeOfDay)
-> Parser Int -> Parser (Int -> TimeOfDay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Int
pHour Parser (Int -> TimeOfDay) -> Parser Int -> Parser TimeOfDay
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> Parser Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
0 )
, Maybe TimeOfDay -> Parser (Maybe TimeOfDay)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe TimeOfDay
forall a. Maybe a
Nothing
]
where
Parser Int
pMinute :: Parser Int = Int -> Int -> Parser Int
pNumBetween Int
1 Int
60
Parser Int
pHour :: Parser Int = Int -> Int -> Parser Int
pNumBetween Int
1 Int
24
pDate :: Parser Date
pDate :: Parser Date
pDate = Parser ()
skipSpaces Parser () -> Parser Date -> Parser Date
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> [Parser Date] -> Parser Date
forall a. [Parser a] -> Parser a
choice
[ String -> String -> Date -> Parser Date
forall a. String -> String -> a -> Parser a
pPrefix String
"tod" String
"ay" Date
Today
, String -> String -> Date -> Parser Date
forall a. String -> String -> a -> Parser a
pPrefix String
"tom" String
"orrow" Date
Tomorrow
, DayOfWeek -> Date
Next (DayOfWeek -> Date) -> Parser DayOfWeek -> Parser Date
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser DayOfWeek
pNext
, (Int, Maybe Int, Maybe Integer) -> Date
Date ((Int, Maybe Int, Maybe Integer) -> Date)
-> Parser (Int, Maybe Int, Maybe Integer) -> Parser Date
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Int, Maybe Int, Maybe Integer)
pDate'
] Parser Date -> Parser () -> Parser Date
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
skipSpaces
where
Parser DayOfWeek
pNext :: Parser DayOfWeek = [Parser DayOfWeek] -> Parser DayOfWeek
forall a. [Parser a] -> Parser a
choice
[ String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"m" String
"onday" DayOfWeek
Monday , String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"tu" String
"esday" DayOfWeek
Tuesday
, String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"w" String
"ednesday" DayOfWeek
Wednesday, String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"th" String
"ursday" DayOfWeek
Thursday
, String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"f" String
"riday" DayOfWeek
Friday , String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"sa" String
"turday" DayOfWeek
Saturday
, String -> String -> DayOfWeek -> Parser DayOfWeek
forall a. String -> String -> a -> Parser a
pPrefix String
"su" String
"nday" DayOfWeek
Sunday
]
numWithoutColon :: Parser Int
numWithoutColon :: Parser Int
numWithoutColon = do
Int
str <- Int -> Int -> Parser Int
pNumBetween Int
1 Int
12
Char
c <- Parser Char
get
if Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':'
then Parser Int
forall a. Parser a
pfail
else Int -> Parser Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
str
pDate' :: Parser (Int, Maybe Int, Maybe Integer)
pDate' :: Parser (Int, Maybe Int, Maybe Integer)
pDate' =
(,,) (Int
-> Maybe Int -> Maybe Integer -> (Int, Maybe Int, Maybe Integer))
-> Parser Int
-> Parser
(Maybe Int -> Maybe Integer -> (Int, Maybe Int, Maybe Integer))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> Parser Int
pNumBetween Int
1 Int
31
Parser
(Maybe Int -> Maybe Integer -> (Int, Maybe Int, Maybe Integer))
-> Parser (Maybe Int)
-> Parser (Maybe Integer -> (Int, Maybe Int, Maybe Integer))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Int -> Parser (Maybe Int)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser ()
skipSpaces Parser () -> Parser Int -> Parser Int
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> [Parser Int] -> Parser Int
forall a. [Parser a] -> Parser a
choice
[ String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"ja" String
"nuary" Int
1 , String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"f" String
"ebruary" Int
2
, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"mar" String
"ch" Int
3 , String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"ap" String
"ril" Int
4
, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"may" String
"" Int
5 , String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"jun" String
"e" Int
6
, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"jul" String
"y" Int
7 , String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"au" String
"gust" Int
8
, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"s" String
"eptember" Int
9 , String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"o" String
"ctober" Int
10
, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"n" String
"ovember" Int
11, String -> String -> Int -> Parser Int
forall a. String -> String -> a -> Parser a
pPrefix String
"d" String
"ecember" Int
12
, Parser Int
numWithoutColon
])
Parser (Maybe Integer -> (Int, Maybe Int, Maybe Integer))
-> Parser (Maybe Integer) -> Parser (Int, Maybe Int, Maybe Integer)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Integer -> Parser (Maybe Integer)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser ()
skipSpaces Parser () -> Parser Integer -> Parser Integer
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Integer
forall a. (Read a, Integral a) => Parser a
num Parser Integer -> (Integer -> Parser Integer) -> Parser Integer
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Integer
i -> Bool -> Parser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
25) Parser () -> Integer -> Parser Integer
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Integer
i)
pPrefix :: String -> String -> a -> Parser a
pPrefix :: forall a. String -> String -> a -> Parser a
pPrefix String
start String
leftover a
ret = do
Parser String -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Parser String -> Parser ()) -> Parser String -> Parser ()
forall a b. (a -> b) -> a -> b
$ String -> Parser String
string String
start
String
l <- (Char -> Bool) -> Parser String
munch (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' ')
Bool -> Parser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (String
l String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
leftover)
a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
ret
pNumBetween :: Int -> Int -> Parser Int
pNumBetween :: Int -> Int -> Parser Int
pNumBetween Int
lo Int
hi = do
Int
n <- Parser Int
forall a. (Read a, Integral a) => Parser a
num
Int
n Int -> Parser () -> Parser Int
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Bool -> Parser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
lo Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
hi)