GitHub

@@ -29,11 +29,13 @@ import Protolude (

2929

hush,

3030

isJust,

3131

optional,

32+

putErrLn,

3233

rightToMaybe,

3334

show,

3435

toStrict,

3536

($),

3637

(&),

38+

(+),

3739

(.),

3840

(<$>),

3941

(<&>),

@@ -70,7 +72,8 @@ import Data.Time.ISO8601.Duration qualified as Iso

7072

import Data.ULID (ULID, ulidFromInteger)

7173

import Data.ULID.TimeStamp (getULIDTimeStamp)

7274

import Data.Vector qualified as V

73-

import Data.Yaml as Yaml (ParseException, decodeEither')

75+

import Data.Yaml (ParseException (InvalidYaml), YamlException (YamlException, YamlParseException), YamlMark (YamlMark))

76+

import Data.Yaml qualified as Yaml

7477

import Database.SQLite.Simple as Sql (Connection, query_)

7578

import FullTask (FullTask)

7679

import Lib (

@@ -723,18 +726,53 @@ data PreEdit

723726

| NoPreEdit

724727725728729+

{-| Edit the task until it is valid YAML and can be decoded.

730+

| Return the the tuple `(task, valid YAML content)`

731+

-}

732+

editUntilValidYaml

733+

:: PreEdit

734+

-> Connection

735+

-> P.ByteString

736+

-> P.ByteString

737+

-> IO (Either ParseException (ImportTask, P.ByteString))

738+

editUntilValidYaml preEdit conn initialYaml wipYaml = do

739+

yamlAfterEdit <- case preEdit of

740+

ApplyPreEdit editFunc -> pure $ editFunc wipYaml

741+

NoPreEdit -> runUserEditorDWIM yamlTemplate wipYaml

742+743+

if yamlAfterEdit == initialYaml

744+

then pure $ Left $ InvalidYaml $ Just $ YamlException "⚠️ Nothing changed"

745+

else do

746+

case yamlAfterEdit & Yaml.decodeEither' of

747+

Left error -> do

748+

case error of

749+

-- Adjust the line and column numbers to be 1-based

750+

InvalidYaml

751+

(Just (YamlParseException prblm ctxt (YamlMark idx line col))) ->

752+

let yamlMark = YamlMark (idx + 1) (line + 1) (col + 1)

753+

in putErrLn $

754+

Yaml.prettyPrintParseException

755+

( InvalidYaml

756+

(Just (YamlParseException prblm ctxt yamlMark))

757+

)

758+

<> "\n"

759+

_ ->

760+

putErrLn $ Yaml.prettyPrintParseException error <> "\n"

761+

editUntilValidYaml preEdit conn initialYaml yamlAfterEdit

762+

---

763+

Right newTask -> do

764+

pure $ Right (newTask, yamlAfterEdit)

765+766+726767

editTaskByTask :: PreEdit -> Connection -> Task -> IO (Doc AnsiStyle)

727768

editTaskByTask preEdit conn taskToEdit = do

728769

taskYaml <- taskToEditableYaml conn taskToEdit

729-

newContent <- case preEdit of

730-

ApplyPreEdit editFunc -> pure $ editFunc taskYaml

731-

NoPreEdit -> runUserEditorDWIM yamlTemplate taskYaml

732-733-

if newContent == taskYaml

734-

then

735-

pure $

736-

"⚠️ Nothing changed" <+> hardline

737-

else do

770+

taskYamlTupleRes <- editUntilValidYaml preEdit conn taskYaml taskYaml

771+

case taskYamlTupleRes of

772+

Left error -> pure $ pretty $ Yaml.prettyPrintParseException error

773+

Right (importTaskRecord, newContent) -> do

774+

effectiveUserName <- getEffectiveUserName

775+

now <- getULIDTimeStamp <&> (show >>> T.toLower)

738776

let

739777

parseMetadata :: Value -> Parser Bool

740778

parseMetadata val = case val of

@@ -747,60 +785,51 @@ editTaskByTask preEdit conn taskToEdit = do

747785748786

hasMetadata =

749787

parseMaybe parseMetadata

750-

=<< (rightToMaybe $ Yaml.decodeEither' newContent :: Maybe Value)

788+

=<< rightToMaybe (Yaml.decodeEither' newContent)

789+790+

taskFixed =

791+

importTaskRecord.task

792+

{ Task.user =

793+

if importTaskRecord.task.user == ""

794+

then T.pack effectiveUserName

795+

else importTaskRecord.task.user

796+

, Task.metadata =

797+

if hasMetadata == Just True

798+

then importTaskRecord.task.metadata

799+

else Nothing

800+

, -- Set to previous value to force SQL trigger to update it

801+

Task.modified_utc = taskToEdit.modified_utc

802+

}

803+

notesCorrectUtc =

804+

importTaskRecord.notes

805+

<&> ( \note ->

806+

note

807+

{ Note.ulid =

808+

if zeroUlidTxt `T.isPrefixOf` note.ulid

809+

then note.ulid & T.replace zeroUlidTxt now

810+

else note.ulid

811+

}

812+

)

751813752-

decodeResult :: Either ParseException ImportTask

753-

decodeResult = Yaml.decodeEither' newContent

814+

updateTask conn taskFixed

754815755-

case decodeResult of

756-

Left error -> die $ show error <> " in task \n" <> show newContent

757-

Right importTaskRecord -> do

758-

effectiveUserName <- getEffectiveUserName

759-

now <- getULIDTimeStamp <&> (show >>> T.toLower)

760-

let

761-

taskFixed =

762-

importTaskRecord.task

763-

{ Task.user =

764-

if importTaskRecord.task.user == ""

765-

then T.pack effectiveUserName

766-

else importTaskRecord.task.user

767-

, Task.metadata =

768-

if hasMetadata == Just True

769-

then importTaskRecord.task.metadata

770-

else Nothing

771-

, -- Set to previous value to force SQL trigger to update it

772-

Task.modified_utc = taskToEdit.modified_utc

773-

}

774-

notesCorrectUtc =

775-

importTaskRecord.notes

776-

<&> ( \note ->

777-

note

778-

{ Note.ulid =

779-

if zeroUlidTxt `T.isPrefixOf` note.ulid

780-

then note.ulid & T.replace zeroUlidTxt now

781-

else note.ulid

782-

}

783-

)

784-785-

updateTask conn taskFixed

786-787-

-- TODO: Remove after it was added to `createSetClosedUtcTrigger`

788-

-- Update again with the same `state` field to avoid firing

789-

-- SQL trigger which would overwrite the `closed_utc` field.

790-

P.when (isJust taskFixed.closed_utc) $ do

791-

now_ <- dateCurrent

792-

updateTask conn taskFixed{Task.modified_utc = show @DateTime now_}

793-794-

tagWarnings <- insertTags conn Nothing taskFixed importTaskRecord.tags

795-

noteWarnings <- insertNotes conn Nothing taskFixed notesCorrectUtc

796-

pure $

797-

tagWarnings

798-

<$$> noteWarnings

799-

<$$> "✏️ Edited task"

800-

<+> dquotes (pretty taskFixed.body)

801-

<+> "with ulid"

802-

<+> dquotes (pretty taskFixed.ulid)

803-

<+> hardline

816+

-- TODO: Remove after it was added to `createSetClosedUtcTrigger`

817+

-- Update again with the same `state` field to avoid firing

818+

-- SQL trigger which would overwrite the `closed_utc` field.

819+

P.when (isJust taskFixed.closed_utc) $ do

820+

now_ <- dateCurrent

821+

updateTask conn taskFixed{Task.modified_utc = show @DateTime now_}

822+823+

tagWarnings <- insertTags conn Nothing taskFixed importTaskRecord.tags

824+

noteWarnings <- insertNotes conn Nothing taskFixed notesCorrectUtc

825+

pure $

826+

tagWarnings

827+

<$$> noteWarnings

828+

<$$> "✏️ Edited task"

829+

<+> dquotes (pretty taskFixed.body)

830+

<+> "with ulid"

831+

<+> dquotes (pretty taskFixed.ulid)

832+

<+> hardline

804833805834806835

editTask :: Config -> Connection -> IdText -> IO (Doc AnsiStyle)

Read the original on github.com ↗