Skip to content

Commit 8df1c65

Browse files
committed
Feat: Support the full ISO8601 durations syntax everywhere
1 parent 2ee1c21 commit 8df1c65

File tree

2 files changed

+43
-43
lines changed

2 files changed

+43
-43
lines changed

tasklite-core/app/Main.hs

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Data.String (fromString)
1818
import qualified Data.Text as T
1919
import Data.Text.Prettyprint.Doc hiding ((<>))
2020
import Data.Text.Prettyprint.Doc.Render.Terminal
21-
import qualified Data.Time.ISO8601.Duration as ISO8601
21+
import qualified Data.Time.ISO8601.Duration as Iso
2222
import Data.Version (showVersion)
2323
import Data.Yaml (decodeFileEither, prettyPrintParseException)
2424
import GHC.IO.Encoding (setLocaleEncoding, utf8)
@@ -59,16 +59,16 @@ data Command
5959
{- Modify -}
6060
| ReadyOn DateTime [IdText]
6161
| WaitTasks [IdText]
62-
| WaitFor Duration [IdText]
62+
| WaitFor Iso.Duration [IdText]
6363
| ReviewTasks [IdText]
64-
| ReviewTasksIn Duration [IdText]
64+
| ReviewTasksIn Iso.Duration [IdText]
6565
| DoTasks [IdText]
6666
| DoOneTask IdText (Maybe [Text])
6767
| EndTasks [IdText]
6868
| TrashTasks [IdText]
6969
| DeleteTasks [IdText]
70-
| RepeatTasks Duration [IdText]
71-
| RecurTasks ISO8601.Duration [IdText]
70+
| RepeatTasks Iso.Duration [IdText]
71+
| RecurTasks Iso.Duration [IdText]
7272
| BoostTasks [IdText]
7373
| HushTasks [IdText]
7474
-- | Modify [IdText] Text -- DSL for modifying a task
@@ -236,17 +236,10 @@ unset_sec = ("{{unset_sec}}", "Unset Commands")
236236
utils_sec = ("{{utils_sec}}", "Utils")
237237

238238

239-
parseDurationInDays :: [Char] -> Maybe Duration
240-
parseDurationInDays =
241-
(fmap (\days -> mempty
242-
{ durationMinutes = Minutes $ round ((days :: Float) * 1440)}))
243-
. readMaybe
244-
245-
246-
parseDurationString :: [Char] -> Either [Char] ISO8601.Duration
239+
parseDurationString :: [Char] -> Either [Char] Iso.Duration
247240
parseDurationString text = text
248241
& fromString
249-
& ISO8601.parseDuration
242+
& Iso.parseDuration
250243

251244

252245
commandParser :: Config -> Parser Command
@@ -281,22 +274,22 @@ commandParser conf =
281274
"Mark a task as waiting (e.g. for feedback) and review it in 3 days")
282275

283276
<> command "waitfor" (toParserInfo (WaitFor
284-
<$> argument (maybeReader parseDurationInDays)
285-
(metavar "NUM_OF_DAYS" <> help "Duration in days \
286-
\(supports fractional values)")
277+
<$> argument (eitherReader parseDurationString)
278+
(metavar "DURATION"
279+
<> help "ISO8601 duration (e.g. P1DT5H for 1 day and 5 hours)")
287280
<*> some (strArgument idsVar))
288-
"Wait x days until it's ready for review")
281+
"Wait DURATION until it's ready for review")
289282

290283
<> command "review" (toParserInfo (ReviewTasks
291284
<$> some (strArgument idsVar))
292285
"Finish review and set new review date in 3 days")
293286

294287
<> command "reviewin" (toParserInfo (ReviewTasksIn
295-
<$> argument (maybeReader parseDurationInDays)
296-
(metavar "NUM_OF_DAYS" <> help "Duration in days \
297-
\(supports fractional values)")
288+
<$> argument (eitherReader parseDurationString)
289+
(metavar "DURATION"
290+
<> help "ISO8601 duration (e.g. P1DT5H for 1 day and 5 hours)")
298291
<*> some (strArgument idsVar))
299-
"Finish review and set new review date in x days")
292+
"Finish review and set new review date in DURATION")
300293

301294
<> command "do" (toParserInfo (DoOneTask
302295
<$> strArgument idsVar
@@ -325,9 +318,9 @@ commandParser conf =
325318
"Delete a task from the database (Attention: Irreversible)")
326319

327320
<> command "repeat" (toParserInfo (RepeatTasks
328-
<$> argument (maybeReader parseDurationInDays)
329-
(metavar "NUM_OF_DAYS" <> help "Number of days \
330-
\(supports fractional values)")
321+
<$> argument (eitherReader parseDurationString)
322+
(metavar "DURATION"
323+
<> help "ISO8601 duration (e.g. P1DT5H for 1 day and 5 hours)")
331324
<*> some (strArgument idsVar))
332325
"Repeat a task x days after its due UTC or after it gets closed \
333326
\(whichever occurs later)")
@@ -831,7 +824,7 @@ executeCLiCommand conf now connection cmd =
831824
prettyUlid ulid = pretty $ fmap
832825
(T.pack . timePrint (toFormat ("YYYY-MM-DD H:MI:S.ms" :: [Char])))
833826
(ulidTextToDateTime ulid)
834-
days3 = mempty {durationHours = 72}
827+
days3 = Iso.DurationDate (Iso.DurDateDay (Iso.DurDay 3) Nothing)
835828

836829
in case cmd of
837830
ListAll -> listAll conf now connection

tasklite-core/source/Lib.hs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Protolude as P
88

99
import Data.Hourglass
1010
import Data.Text as T
11-
import qualified Data.Time.ISO8601.Duration as Iso8601
11+
import qualified Data.Time.ISO8601.Duration as Iso
1212
import Data.ULID
1313
import Data.Coerce
1414
import Data.Yaml as Yaml
@@ -339,15 +339,18 @@ setReadyUtc conf connection datetime ids = do
339339
pure $ vsep docs
340340

341341

342-
waitFor :: Config -> Connection -> Duration -> [Text] -> IO (Doc AnsiStyle)
342+
waitFor
343+
:: Config -> Connection -> Iso.Duration -> [Text] -> IO (Doc AnsiStyle)
343344
waitFor conf connection duration ids = do
344345
docs <- forM ids $ \idSubstr ->
345346
execWithTask conf connection idSubstr $ \task -> do
346347
now <- timeCurrentP
347348
let
348349
taskUlid@(TaskUlid idText) = primaryKey task
349350
nowAsText = (pack . timePrint (utcFormat conf)) now
350-
threeDays = (pack . timePrint (utcFormat conf)) (now `timeAdd` duration)
351+
threeDays = (pack . timePrint (utcFormat conf))
352+
(utcTimeToDateTime $ Iso.addDuration duration $
353+
dateTimeToUtcTime $ timeFromElapsedP now)
351354
prettyBody = dquotes (pretty $ Task.body task)
352355
prettyId = dquotes (pretty idText)
353356

@@ -373,18 +376,21 @@ waitFor conf connection duration ids = do
373376

374377
waitTasks :: Config -> Connection -> [Text] -> IO (Doc AnsiStyle)
375378
waitTasks conf connection =
376-
waitFor conf connection $ mempty { durationHours = 72 }
379+
waitFor conf connection $
380+
Iso.DurationDate (Iso.DurDateDay (Iso.DurDay 3) Nothing)
377381

378382

379383
reviewTasksIn :: Config -> Connection
380-
-> Duration -> [Text] -> IO (Doc AnsiStyle)
381-
reviewTasksIn conf connection days ids = do
384+
-> Iso.Duration -> [Text] -> IO (Doc AnsiStyle)
385+
reviewTasksIn conf connection duration ids = do
382386
docs <- forM ids $ \idSubstr -> do
383387
execWithTask conf connection idSubstr $ \task -> do
384388
now <- timeCurrentP
385389
let
386390
taskUlid@(TaskUlid idText) = primaryKey task
387-
xDays = (pack . timePrint (utcFormat conf)) (now `timeAdd` days)
391+
xDays = (pack . timePrint (utcFormat conf))
392+
(utcTimeToDateTime $ Iso.addDuration duration $
393+
dateTimeToUtcTime $ timeFromElapsedP now)
388394
prettyBody = dquotes (pretty $ Task.body task)
389395
prettyId = dquotes (pretty idText)
390396
warningStart = "⚠️ Task" <+> prettyBody <+> "with id" <+> prettyId
@@ -498,14 +504,14 @@ createNextRecurrence conf connection task = do
498504
isoDurEither =
499505
durTextEither
500506
<&> encodeUtf8
501-
>>= Iso8601.parseDuration
507+
>>= Iso.parseDuration
502508

503509
showEither e = e
504510
& (either (const Nothing) Just)
505511
<&> utcTimeToDateTime
506512
<&> showDateTime
507513

508-
nextDueMb = liftA2 Iso8601.addDuration isoDurEither
514+
nextDueMb = liftA2 Iso.addDuration isoDurEither
509515
(maybeToEither "Task has no due UTC" (dueUtcMb <&> dateTimeToUtcTime))
510516

511517
runBeamSqlite connection $ do
@@ -519,13 +525,13 @@ createNextRecurrence conf connection task = do
519525
, Task.due_utc = val_ $ nextDueMb & showEither
520526

521527
, Task.awake_utc = val_ $
522-
(liftA2 Iso8601.addDuration isoDurEither
528+
(liftA2 Iso.addDuration isoDurEither
523529
(maybeToEither "Task has no awake UTC"
524530
((Task.awake_utc task) >>= parseUtc <&> dateTimeToUtcTime)))
525531
& showEither
526532

527533
, Task.ready_utc = val_ $
528-
(liftA2 Iso8601.addDuration isoDurEither
534+
(liftA2 Iso.addDuration isoDurEither
529535
(maybeToEither "Task has no ready UTC"
530536
((Task.ready_utc task) >>= parseUtc <&> dateTimeToUtcTime)))
531537
& showEither
@@ -661,9 +667,9 @@ durationToIso dur =
661667

662668

663669
repeatTasks ::
664-
Config -> Connection -> Duration -> [IdText] -> IO (Doc AnsiStyle)
670+
Config -> Connection -> Iso.Duration -> [IdText] -> IO (Doc AnsiStyle)
665671
repeatTasks conf connection duration ids = do
666-
let durIso = durationToIso duration
672+
let durationIsoText = decodeUtf8 $ Iso.formatDuration duration
667673

668674
docs <- forM ids $ \idSubstr ->
669675
execWithTask conf connection idSubstr $ \task -> do
@@ -677,28 +683,29 @@ repeatTasks conf connection duration ids = do
677683
runBeamSqlite connection $ runUpdate $
678684
update (_tldbTasks taskLiteDb)
679685
(\task_ -> mconcat
680-
[ (Task.repetition_duration task_) <-. val_ (Just durIso)
686+
[ (Task.repetition_duration task_) <-. val_ (Just durationIsoText)
681687
, (Task.group_ulid task_) <-. val_ (Just groupUlid)
682688
])
683689
(\task_ -> primaryKey task_ ==. val_ taskUlid)
684690

685691
pure $ "📅 Set repeat duration of task" <+> prettyBody
686692
<+> "with id" <+> prettyId
687-
<+> "to" <+> dquotes (pretty $ durIso)
693+
<+> "to" <+> dquotes (pretty $ durationIsoText)
688694

689695
pure $ vsep docs
690696

691697

692698
recurTasks ::
693-
Config -> Connection -> Iso8601.Duration -> [IdText] -> IO (Doc AnsiStyle)
699+
Config -> Connection -> Iso.Duration -> [IdText] -> IO (Doc AnsiStyle)
694700
recurTasks conf connection duration ids = do
701+
let durationIsoText = decodeUtf8 $ Iso.formatDuration duration
702+
695703
docs <- forM ids $ \idSubstr ->
696704
execWithTask conf connection idSubstr $ \task -> do
697705
let
698706
taskUlid@(TaskUlid idText) = primaryKey task
699707
prettyBody = dquotes (pretty $ Task.body task)
700708
prettyId = dquotes (pretty idText)
701-
durationIsoText = decodeUtf8 $ Iso8601.formatDuration duration
702709

703710
groupUlid <- formatUlid getULID
704711

0 commit comments

Comments
 (0)