diff --git a/CHANGELOG.md b/CHANGELOG.md index 3665142..7da270b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## Next up - **[ FEATURE ]** Add new command `klog switch`, that stops a previously ongoing activity (open time range), and starts a new one. +- **[ FEATURE ]** `klog start --resume` now falls back to the previous + record for determining the last entry summary. ## v6.1 - **[ FEATURE ]** Add new flag `klog start --resume`, which takes over the diff --git a/klog/app/cli/start.go b/klog/app/cli/start.go index 9c27567..2f1da7f 100644 --- a/klog/app/cli/start.go +++ b/klog/app/cli/start.go @@ -5,6 +5,8 @@ import ( "github.com/jotaen/klog/klog/app" "github.com/jotaen/klog/klog/app/cli/lib" "github.com/jotaen/klog/klog/parser/reconciling" + "github.com/jotaen/klog/klog/parser/txt" + "github.com/jotaen/klog/klog/service" ) type Start struct { @@ -34,14 +36,16 @@ func (opt *Start) Run(ctx app.Context) app.Error { ctx.Config().DefaultShouldTotal.Map(func(s klog.ShouldTotal) { additionalData.ShouldTotal = s }) + spy := PreviousRecordSpy{} return lib.Reconcile(ctx, lib.ReconcileOpts{OutputFileArgs: opt.OutputFileArgs, WarnArgs: opt.WarnArgs}, []reconciling.Creator{ + spy.phonyCreator(date), reconciling.NewReconcilerAtRecord(date), reconciling.NewReconcilerForNewRecord(date, opt.DateFormat(ctx.Config()), additionalData), }, func(reconciler *reconciling.Reconciler) error { - summary, sErr := opt.Summary(reconciler.Record) + summary, sErr := opt.Summary(reconciler.Record, spy.PreviousRecord) if sErr != nil { return sErr } @@ -50,7 +54,8 @@ func (opt *Start) Run(ctx app.Context) app.Error { ) } -func (opt *Start) Summary(r klog.Record) (klog.EntrySummary, app.Error) { +func (opt *Start) Summary(currentRecord klog.Record, previousRecord klog.Record) (klog.EntrySummary, app.Error) { + // Check for conflicting flags. if opt.SummaryText != nil && opt.Resume { return nil, app.NewErrorWithCode( app.LOGICAL_ERROR, @@ -59,12 +64,51 @@ func (opt *Start) Summary(r klog.Record) (klog.EntrySummary, app.Error) { nil, ) } + + // Return summary flag, if specified. if opt.SummaryText != nil { return opt.SummaryText, nil } - entriesCount := len(r.Entries()) - if opt.Resume && entriesCount > 0 { - return r.Entries()[entriesCount-1].Summary(), nil + + // Skip if resume flag wasn’t specified. + if !opt.Resume { + return nil, nil + } + + // Return summary of last entry from current record, if it has any entries. + if len(currentRecord.Entries()) > 0 { + return lastEntrySummary(currentRecord), nil } + + // Return summary of last entry from previous record, if exists. + if previousRecord != nil { + return lastEntrySummary(previousRecord), nil + } + return nil, nil } + +func lastEntrySummary(r klog.Record) klog.EntrySummary { + entriesCount := len(r.Entries()) + return r.Entries()[entriesCount-1].Summary() +} + +type PreviousRecordSpy struct { + PreviousRecord klog.Record +} + +// phonyCreator is a no-op “pass-through” creator, whose only purpose it is to hook into +// the reconciler-creation mechanism, to get a handle on the records for determining +// the previous record. +func (p *PreviousRecordSpy) phonyCreator(currentDate klog.Date) reconciling.Creator { + return func(records []klog.Record, _ []txt.Block) *reconciling.Reconciler { + for _, r := range service.Sort(records, false) { + if r.Date().IsAfterOrEqual(currentDate) { + continue + } + p.PreviousRecord = r + return nil + } + return nil + } +} diff --git a/klog/app/cli/start_test.go b/klog/app/cli/start_test.go index 67aa15a..ccae49c 100644 --- a/klog/app/cli/start_test.go +++ b/klog/app/cli/start_test.go @@ -264,7 +264,7 @@ default_rounding = 60m } func TestStartWithResume(t *testing.T) { - t.Run("No previous entry -> Empty entry summary", func(t *testing.T) { + t.Run("No previous entry, no previous record -> Empty entry summary", func(t *testing.T) { state, err := NewTestingContext()._SetRecords(`1623-12-13 `)._SetNow(1623, 12, 13, 12, 49)._Run((&Start{ Resume: true, @@ -275,6 +275,25 @@ func TestStartWithResume(t *testing.T) { `, state.writtenFileContents) }) + t.Run("No previous entry, but previous record -> Take over from previous record", func(t *testing.T) { + state, err := NewTestingContext()._SetRecords(` +1623-12-12 + 14:00 - 15:00 Did something + 10m Some activity +`)._SetNow(1623, 12, 13, 12, 49)._Run((&Start{ + Resume: true, + }).Run) + require.Nil(t, err) + assert.Equal(t, ` +1623-12-12 + 14:00 - 15:00 Did something + 10m Some activity + +1623-12-13 + 12:49 - ? Some activity +`, state.writtenFileContents) + }) + t.Run("No previous entry summary -> Empty entry summary", func(t *testing.T) { state, err := NewTestingContext()._SetRecords(`1623-12-13 8:13 - 9:44