X.P.OrgMode: Add ability to schedule hours/minutes

This commit is contained in:
slotThe
2021-03-30 18:12:03 +02:00
parent db8e47e0b4
commit fd20202c23

View File

@@ -76,7 +76,8 @@ above you can write
There is also some scheduling and deadline functionality present. They There is also some scheduling and deadline functionality present. They
are initiated by entering @+s@ or @+d@ into the prompt respectively, are initiated by entering @+s@ or @+d@ into the prompt respectively,
followed by a date. Any of the following are valid dates: followed by a date and a time of day. Any of the following are valid
dates:
- today - today
- tomorrow - tomorrow
@@ -91,21 +92,29 @@ into the future, e.g. if today is Monday and you schedule something for
Monday, you will actually schedule it for the /next/ Monday (the one in Monday, you will actually schedule it for the /next/ Monday (the one in
seven days). seven days).
The time is specified in the @HH:MM@ format. The minutes may be
omitted, in which case @00@ will be substituted.
A few examples are probably in order. Suppose we have bound the key A few examples are probably in order. Suppose we have bound the key
above, pressed it, and are now confronted with a prompt: above, pressed it, and are now confronted with a prompt:
- @hello +s today@ would create a TODO note with the header @hello@ - @hello +s today@ would create a TODO note with the header @hello@
and would schedule that for today's date. and would schedule that for today's date.
- @hello +d today@ works just like above, but creates a deadline. - @hello +s today 12@ schedules the note for today at 12:00.
- @hello +s today 12:30@ schedules it for today at 12:30.
- @hello +d today 12:30@ works just like above, but creates a
deadline.
- @hello +s thu@ would schedule the note for next thursday. - @hello +s thu@ would schedule the note for next thursday.
- @hello +s 11@ would schedule the note for the 11th of this month and - @hello +s 11@ would schedule it for the 11th of this month and this
this year. year.
- @hello +s 11 jan 2013@ would schedule it for the 11th of January - @hello +s 11 jan 2013@ would schedule the note for the 11th of
2013. January 2013.
There's also the possibility to take what's currently in the primary There's also the possibility to take what's currently in the primary
selection and paste that as the content of the created note. This is selection and paste that as the content of the created note. This is
@@ -189,6 +198,20 @@ mkOrgPrompt xpc oc@OrgMode{ todoHeader, orgFile, clpSupport } =
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Time -- Time
-- | A 'Time' is a 'Date' with the possibility of having a specified
-- @HH:MM@ time.
data Time = Time
{ date :: Date
, tod :: Maybe TimeOfDay
}
-- | The time in HH:MM.
data TimeOfDay = TimeOfDay Int Int
instance Show TimeOfDay where
show :: TimeOfDay -> String
show (TimeOfDay h m) = show h <> ":" <> show m <> if m <= 9 then "0" else ""
-- | Type for specifying exactly which day one wants. -- | Type for specifying exactly which day one wants.
data Date data Date
= Today = Today
@@ -200,20 +223,23 @@ data Date
| Date (Int, Maybe Int, Maybe Integer) | Date (Int, Maybe Int, Maybe Integer)
-- ^ Manual date entry in the format DD [MM] [YYYY] -- ^ Manual date entry in the format DD [MM] [YYYY]
toOrgFmt :: Day -> String toOrgFmt :: Maybe TimeOfDay -> Day -> String
toOrgFmt d = mconcat ["<", isoTime, " ", take 3 $ show (dayOfWeek d), ">"] toOrgFmt tod day =
mconcat ["<", isoDay, " ", take 3 $ show (dayOfWeek day), time, ">"]
where where
isoTime :: String = formatTime defaultTimeLocale (iso8601DateFormat Nothing) d time :: String = maybe "" ((' ' :) . show) tod
isoDay :: String = formatTime defaultTimeLocale (iso8601DateFormat Nothing) day
-- | Pretty print a 'Date' to reflect the actual date. -- | Pretty print a 'Date' and an optional time to reflect the actual
ppDate :: Date -> IO String -- date.
ppDate date = do ppDate :: Time -> IO String
ppDate Time{ date, tod } = do
curTime <- getCurrentTime curTime <- getCurrentTime
let curDay = utctDay curTime let curDay = utctDay curTime
(y, m, _) = toGregorian curDay (y, m, _) = toGregorian curDay
diffToDay d = diffBetween d (dayOfWeek curDay) diffToDay d = diffBetween d (dayOfWeek curDay)
pure . toOrgFmt $ case date of pure . toOrgFmt tod $ case date of
Today -> curDay Today -> curDay
Tomorrow -> utctDay $ addDays 1 curTime Tomorrow -> utctDay $ addDays 1 curTime
Next wday -> utctDay $ addDays (diffToDay wday) curTime Next wday -> utctDay $ addDays (diffToDay wday) curTime
@@ -268,18 +294,18 @@ instance Enum DayOfWeek where
-- | An @org-mode@ style note. -- | An @org-mode@ style note.
data Note data Note
= Scheduled String Date = Scheduled String Time
| Deadline String Date | Deadline String Time
| NormalMsg String | NormalMsg String
-- | Pretty print a given 'Note'. -- | Pretty print a given 'Note'.
ppNote :: String -> String -> Note -> IO String ppNote :: String -> String -> Note -> IO String
ppNote clp todo = \case ppNote clp todo = \case
Scheduled str date -> mkLine str "SCHEDULED: " date Scheduled str time -> mkLine str "SCHEDULED: " time
Deadline str date -> mkLine str "DEADLINE: " date Deadline str time -> mkLine str "DEADLINE: " time
NormalMsg str -> pure . mconcat $ ["* ", todo, " ", str, clp] NormalMsg str -> pure . mconcat $ ["* ", todo, " ", str, clp]
where where
mkLine :: String -> String -> Date -> IO String mkLine :: String -> String -> Time -> IO String
mkLine inp sched mkLine inp sched
= fmap (\d -> mconcat ["* ", todo, " ", inp, "\n ", sched, d, clp]) = fmap (\d -> mconcat ["* ", todo, " ", inp, "\n ", sched, d, clp])
. ppDate . ppDate
@@ -290,8 +316,8 @@ ppNote clp todo = \case
-- | Parse the given string into a 'Note'. -- | Parse the given string into a 'Note'.
pInput :: String -> Maybe Note pInput :: String -> Maybe Note
pInput inp = fmap fst . listToMaybe . (`readP_to_S` inp) . lchoice $ pInput inp = fmap fst . listToMaybe . (`readP_to_S` inp) . lchoice $
[ Scheduled <$> getLast "+s" <*> pDate [ Scheduled <$> getLast "+s" <*> (Time <$> pDate <*> pTimeOfDay)
, Deadline <$> getLast "+d" <*> pDate , Deadline <$> getLast "+d" <*> (Time <$> pDate <*> pTimeOfDay)
, NormalMsg <$> munch1 (const True) , NormalMsg <$> munch1 (const True)
] ]
where where
@@ -305,6 +331,14 @@ pInput inp = fmap fst . listToMaybe . (`readP_to_S` inp) . lchoice $
then pure $ consumed <> next then pure $ consumed <> next
else go $ consumed <> next <> next' else go $ consumed <> next <> next'
-- | Try to parse a 'Time'.
pTimeOfDay :: ReadP (Maybe TimeOfDay)
pTimeOfDay = lchoice
[ Just <$> (TimeOfDay <$> pInt <* string ":" <*> pInt ) -- HH:MM
, Just <$> (TimeOfDay <$> pInt <*> pure 0) -- HH
, pure Nothing
]
-- | Parse a 'Date'. -- | Parse a 'Date'.
pDate :: ReadP Date pDate :: ReadP Date
pDate = skipSpaces *> lchoice pDate = skipSpaces *> lchoice
@@ -312,13 +346,13 @@ pDate = skipSpaces *> lchoice
, Tomorrow <$ string "tom" , Tomorrow <$ string "tom"
, Next <$> pNext , Next <$> pNext
, Date <$> pDate1 <++ pDate2 <++ pDate3 , Date <$> pDate1 <++ pDate2 <++ pDate3
] ] <* munch (/= ' ') <* skipSpaces -- cleanup
where where
pNext :: ReadP DayOfWeek = lchoice pNext :: ReadP DayOfWeek = lchoice
[ Monday <$ string "m" , Tuesday <$ string "tu", Wednesday <$ string "w" [ Monday <$ string "m" , Tuesday <$ string "tu", Wednesday <$ string "w"
, Thursday <$ string "th", Friday <$ string "f" , Saturday <$ string "sa" , Thursday <$ string "th", Friday <$ string "f" , Saturday <$ string "sa"
, Sunday <$ string "su" , Sunday <$ string "su"
] <* munch (/= ' ') ]
-- XXX: This is really horrible, but I can't see a way to not have -- XXX: This is really horrible, but I can't see a way to not have
-- exponential blowup with ReadP otherwise. -- exponential blowup with ReadP otherwise.
@@ -331,14 +365,14 @@ pDate = skipSpaces *> lchoice
-> (ReadP Integer -> ReadP (f Integer)) -> (ReadP Integer -> ReadP (f Integer))
-> ReadP (Int, f Int, f Integer) -> ReadP (Int, f Int, f Integer)
pDate' p p' = pDate' p p' =
(,,) <$> pInt <* skipSpaces (,,) <$> pInt
<*> p (lchoice <*> p (skipSpaces *> lchoice
[ 1 <$ string "ja" , 2 <$ string "f" , 3 <$ string "mar" [ 1 <$ string "ja" , 2 <$ string "f" , 3 <$ string "mar"
, 4 <$ string "ap" , 5 <$ string "may", 6 <$ string "jun" , 4 <$ string "ap" , 5 <$ string "may", 6 <$ string "jun"
, 7 <$ string "jul", 8 <$ string "au" , 9 <$ string "s" , 7 <$ string "jul", 8 <$ string "au" , 9 <$ string "s"
, 10 <$ string "o" , 11 <$ string "n" , 12 <$ string "d" , 10 <$ string "o" , 11 <$ string "n" , 12 <$ string "d"
]) <* skipSpaces ])
<*> p' pInt <*> p' (skipSpaces *> pInt)
-- | Parse a number. -- | Parse a number.
pInt :: (Read a, Integral a) => ReadP a pInt :: (Read a, Integral a) => ReadP a