Skip to content

Commit

Permalink
Optionally amend klog print output with total values
Browse files Browse the repository at this point in the history
* Preserve context data when serialising

* Remove leading newline from report output

* Optionally prefix `print` output with totals

* Rephrase help text

* Add test case for empty output
  • Loading branch information
jotaen authored Oct 1, 2022
1 parent 61d0c8d commit 9f7a4c9
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 33 deletions.
2 changes: 1 addition & 1 deletion klog/app/cli/lib/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func Reconcile(ctx app.Context, opts ReconcileOpts, creators []reconciling.Creat
if err != nil {
return err
}
ctx.Print("\n" + parser.SerialiseRecords(ctx.Serialiser(), result.Record) + "\n")
ctx.Print("\n" + parser.SerialiseRecords(ctx.Serialiser(), result.Record).ToString() + "\n")
opts.WarnArgs.PrintWarnings(ctx, ToRecords(result.AllRecords))
return nil
}
Expand Down
72 changes: 71 additions & 1 deletion klog/app/cli/print.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package cli

import (
"github.com/jotaen/klog/klog"
"github.com/jotaen/klog/klog/app"
"github.com/jotaen/klog/klog/app/cli/lib"
"github.com/jotaen/klog/klog/parser"
"github.com/jotaen/klog/klog/service"
"strings"
)

type Print struct {
WithTotals bool `name:"with-totals" help:"Amend output with evaluated total times"`
lib.FilterArgs
lib.SortArgs
lib.WarnArgs
Expand All @@ -30,8 +34,74 @@ func (opt *Print) Run(ctx app.Context) error {
return nil
}
records = opt.ApplySort(records)
ctx.Print("\n" + parser.SerialiseRecords(ctx.Serialiser(), records...) + "\n")
serialisedRecords := parser.SerialiseRecords(ctx.Serialiser(), records...)
output := func() string {
if opt.WithTotals {
return printWithDurations(ctx.Serialiser(), serialisedRecords)
}
return "\n" + serialisedRecords.ToString()
}()
ctx.Print(output + "\n")

opt.WarnArgs.PrintWarnings(ctx, records)
return nil
}

func printWithDurations(serialiser parser.Serialiser, ls parser.Lines) string {
type Prefix struct {
d klog.Duration
column int
}
var prefixes []*Prefix
maxColumnLengths := []int{0, 0}
var previousRecord klog.Record
previousEntry := -1
for _, l := range ls {
prefix := func() *Prefix {
if l.Record == nil {
previousRecord = nil
previousEntry = -1
return nil
}
if previousRecord == nil {
previousRecord = l.Record
return &Prefix{service.Total(l.Record), 0}
}
if l.EntryI != -1 && l.EntryI != previousEntry {
previousEntry = l.EntryI
return &Prefix{l.Record.Entries()[l.EntryI].Duration(), 1}
} else {
return nil
}
}()
prefixes = append(prefixes, prefix)
if prefix != nil && len(prefix.d.ToString()) > maxColumnLengths[prefix.column] {
maxColumnLengths[prefix.column] = len(prefix.d.ToString())
}
}
RECORD_SEPARATOR := strings.Repeat("-", maxColumnLengths[0]) + "-+-" + strings.Repeat("-", maxColumnLengths[1])
result := RECORD_SEPARATOR + "-+ " + "\n"
for i, l := range ls {
prefixText := ""
p := prefixes[i]
if l.Record == nil {
prefixText = RECORD_SEPARATOR
prefixText += "-+ "
} else {
column := []string{strings.Repeat(" ", maxColumnLengths[0]), strings.Repeat(" ", maxColumnLengths[1])}
if p != nil {
column[p.column] = strings.Repeat(" ", maxColumnLengths[0]-len(p.d.ToString()))
column[p.column] += serialiser.Duration(p.d)
}
prefixText += column[0]
prefixText += " | "
prefixText += column[1]
prefixText += " | "
}
result += prefixText
result += l.Text
result += "\n"
}
result += RECORD_SEPARATOR + "-+ "
return result
}
53 changes: 50 additions & 3 deletions klog/app/cli/print_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@ import (
)

func TestPrintOutEmptyInput(t *testing.T) {
state, err := NewTestingContext()._SetRecords(``)._Run((&Print{}).Run)
require.Nil(t, err)
assert.Equal(t, "", state.printBuffer)
{
state, err := NewTestingContext()._SetRecords(``)._Run((&Print{}).Run)
require.Nil(t, err)
assert.Equal(t, "", state.printBuffer)
}
{
state, err := NewTestingContext()._SetRecords(``)._Run((&Print{
WithTotals: true,
}).Run)
require.Nil(t, err)
assert.Equal(t, "", state.printBuffer)
}
}

func TestPrintOutRecord(t *testing.T) {
Expand Down Expand Up @@ -69,3 +78,41 @@ func TestPrintOutRecordsInChronologicalOrder(t *testing.T) {
_Run((&Print{SortArgs: lib.SortArgs{Sort: "desc"}}).Run)
assert.Equal(t, "\n2018-02-01\n\n2018-01-31\n\n2018-01-30\n\n", stateSortedDesc.printBuffer)
}

func TestPrintRecordsWithDurations(t *testing.T) {
state, err := NewTestingContext()._SetNow(2018, 02, 07, 19, 00)._SetRecords(`
2018-01-31
Hello #world
1h
2018-02-04
15:00 - 17:22
-1h1m
2018-02-07
35m
Foo
18:00 - ? I just
started something
`)._Run((&Print{
WithTotals: true,
}).Run)
require.Nil(t, err)
assert.Equal(t, `
------+-------+
1h | | 2018-01-31
| | Hello #world
| 1h | 1h
------+-------+
1h21m | | 2018-02-04
| 2h22m | 15:00 - 17:22
| -1h1m | -1h1m
------+-------+
35m | | 2018-02-07
| 35m | 35m
| | Foo
| 0m | 18:00 - ? I just
| | started something
------+-------+
`, state.printBuffer)
}
1 change: 0 additions & 1 deletion klog/app/cli/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ func (opt *Report) Run(ctx app.Context) error {
if opt.Diff {
table.Fill("=").Fill("=")
}
ctx.Print("\n")
grandTotal := service.Total(records...)

// Footer
Expand Down
2 changes: 1 addition & 1 deletion klog/parser/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ lines and contains a #tag as well.
7:00 - ?
`
rs, _ := Parse(text)
s := SerialiseRecords(plainSerialiser{}, rs[0])
s := SerialiseRecords(plainSerialiser{}, rs[0]).ToString()
assert.Equal(t, text, s)
}
60 changes: 39 additions & 21 deletions klog/parser/serialiser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,50 +17,68 @@ type Serialiser interface {
Time(klog.Time) string
}

type Line struct {
Text string
Record klog.Record
EntryI int
}

type Lines []Line

func (ls Lines) ToString() string {
result := ""
for _, l := range ls {
result += l.Text + canonicalStyle.LineEnding.Get()
}
return result
}

// SerialiseRecords serialises records into the canonical string representation.
// (So it doesn’t and cannot restore the original formatting!)
func SerialiseRecords(s Serialiser, rs ...klog.Record) string {
var text []string
for _, r := range rs {
text = append(text, serialiseRecord(s, r))
func SerialiseRecords(s Serialiser, rs ...klog.Record) Lines {
var lines []Line
for i, r := range rs {
lines = append(lines, serialiseRecord(s, r)...)
if i < len(rs)-1 {
lines = append(lines, Line{"", nil, -1})
}
}
return strings.Join(text, "\n")
return lines
}

var canonicalStyle = DefaultStyle()

func serialiseRecord(s Serialiser, r klog.Record) string {
text := ""
text += s.Date(r.Date())
func serialiseRecord(s Serialiser, r klog.Record) []Line {
var lines []Line
headline := s.Date(r.Date())
if r.ShouldTotal().InMinutes() != 0 {
text += " (" + s.ShouldTotal(r.ShouldTotal()) + ")"
headline += " (" + s.ShouldTotal(r.ShouldTotal()) + ")"
}
text += canonicalStyle.LineEnding.Get()
lines = append(lines, Line{headline, r, -1})
if r.Summary() != nil {
text += s.Summary(SummaryText(r.Summary())) + canonicalStyle.LineEnding.Get()
lines = append(lines, Line{s.Summary(SummaryText(r.Summary())), r, -1})
}
for _, e := range r.Entries() {
text += canonicalStyle.Indentation.Get()
text += klog.Unbox[string](&e,
for entryI, e := range r.Entries() {
entryValue := klog.Unbox[string](&e,
func(r klog.Range) string { return s.Range(r) },
func(d klog.Duration) string { return s.Duration(d) },
func(o klog.OpenRange) string { return s.OpenRange(o) },
)
lines = append(lines, Line{canonicalStyle.Indentation.Get() + entryValue, r, entryI})
for i, l := range e.Summary().Lines() {
summaryText := s.Summary([]string{l})
if i == 0 && l != "" {
text += " " // separator
lines[len(lines)-1].Text += " " + summaryText
} else if i >= 1 {
text += canonicalStyle.LineEnding.Get() + canonicalStyle.Indentation.Get() + canonicalStyle.Indentation.Get()
lines = append(lines, Line{canonicalStyle.Indentation.Get() + canonicalStyle.Indentation.Get() + summaryText, r, entryI})
}
text += s.Summary([]string{l})
}
text += canonicalStyle.LineEnding.Get()
}
return text
return lines
}

type SummaryText []string

func (s SummaryText) ToString() string {
return strings.Join(s, canonicalStyle.LineEnding.Get())
}

var canonicalStyle = DefaultStyle()
10 changes: 5 additions & 5 deletions klog/parser/serialiser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ func (ps plainSerialiser) SignedDuration(x klog.Duration) string { return x.ToSt
func (ps plainSerialiser) Time(x klog.Time) string { return x.ToString() }

func TestSerialiseNoRecordsToEmptyString(t *testing.T) {
text := SerialiseRecords(plainSerialiser{}, []klog.Record{}...)
text := SerialiseRecords(plainSerialiser{}, []klog.Record{}...).ToString()
assert.Equal(t, "", text)
}

func TestSerialiseEndsWithNewlineIfContainsContent(t *testing.T) {
text := SerialiseRecords(plainSerialiser{}, klog.NewRecord(klog.Ɀ_Date_(2020, 01, 15)))
text := SerialiseRecords(plainSerialiser{}, klog.NewRecord(klog.Ɀ_Date_(2020, 01, 15))).ToString()
lastChar := []rune(text)[len(text)-1]
assert.Equal(t, '\n', lastChar)
}

func TestSerialiseRecordWithMinimalRecord(t *testing.T) {
text := SerialiseRecords(plainSerialiser{}, klog.NewRecord(klog.Ɀ_Date_(2020, 01, 15)))
text := SerialiseRecords(plainSerialiser{}, klog.NewRecord(klog.Ɀ_Date_(2020, 01, 15))).ToString()
assert.Equal(t, `2020-01-15
`, text)
}
Expand All @@ -45,7 +45,7 @@ func TestSerialiseRecordWithCompleteRecord(t *testing.T) {
r.AddDuration(klog.NewDuration(-1, -51), nil)
r.AddRange(klog.Ɀ_Range_(klog.Ɀ_TimeYesterday_(23, 23), klog.Ɀ_Time_(4, 3)), nil)
r.AddRange(klog.Ɀ_Range_(klog.Ɀ_Time_(22, 0), klog.Ɀ_TimeTomorrow_(0, 1)), nil)
text := SerialiseRecords(plainSerialiser{}, r)
text := SerialiseRecords(plainSerialiser{}, r).ToString()
assert.Equal(t, `2020-01-15 (7h30m!)
This is a
multiline summary
Expand All @@ -67,7 +67,7 @@ func TestSerialiseMultipleRecords(t *testing.T) {
text := SerialiseRecords(plainSerialiser{}, []klog.Record{
klog.NewRecord(klog.Ɀ_Date_(2020, 01, 15)),
klog.NewRecord(klog.Ɀ_Date_(2020, 01, 20)),
}...)
}...).ToString()
assert.Equal(t, `2020-01-15
2020-01-20
Expand Down

0 comments on commit 9f7a4c9

Please sign in to comment.