Documentation
¶
Overview ¶
Package twext provides a library for implementing timewarrior extensions in golang.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/aibor/timewarrior-extensions/twext"
)
func main() {
stdin := strings.NewReader(`color: on
reports.day.axis: internal
[
{"id":3,"start":"20240629T102128Z","end":"20240629T102131Z"},
{"id":2,"start":"20240630T143940Z","end":"20240630T143943Z"},
{"id":1,"start":"20240630T144010Z"}
]
`)
reader := twext.NewReader(stdin)
cfg, err := reader.ReadConfig()
if err != nil {
panic("cannot read config section: " + err.Error())
}
fmt.Println("color:", cfg["color"])
entries, err := reader.ReadEntries()
if err != nil {
panic("cannot read entries: " + err.Error())
}
groups := twext.Group(
entries,
func(e twext.Entry) int {
return e.Start.Day()
},
func(r int, _ twext.Entry) int {
return r + 1
},
)
fmt.Println("29:", groups[29])
fmt.Println("30:", groups[30])
}
Output: color: on 29: 1 30: 2
Index ¶
Examples ¶
Constants ¶
const DateFmt = "20060102T150405Z07"
DateFmt is the date format used by timewarrior.
Variables ¶
var ( // ErrDateUnmarshalNotString is returned in case the value given to the // JSON unmarshaller is not a string. ErrDateUnmarshalNotString = errors.New("input is not a JSON string") // ErrConfigInvalidLine is returned if the line can not be split into a // key and value part. ErrConfigInvalidLine = errors.New("config line has invalid format") // ErrConfigEmpty is returned if the config section is empty. ErrConfigEmpty = errors.New("config is empty") // ErrReaderConfigConsumed is returned in case the config section is // tried to be read again. ErrReaderConfigConsumed = errors.New("config section already consumed") // ErrReaderConfigNotConsumed is returned if the entries are tried to be // read before the config section has been read. ErrReaderConfigNotConsumed = errors.New("config section not read yet") )
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config map[ConfigKey]ConfigValue
Config is a collection of configuration directives.
type ConfigKey ¶
type ConfigKey string
ConfigKey is an e complete config key string.
type ConfigValue ¶
type ConfigValue string
ConfigValue is a config value string.
func (ConfigValue) Bool ¶
func (v ConfigValue) Bool() bool
Bool returns true if the ConfigValue matches on of the defined values indication trueness.
func (ConfigValue) Duration ¶ added in v0.1.1
func (v ConfigValue) Duration() (time.Duration, error)
Duration tries to parse the ConfigValue as time.Duration. It returns an error if the string can not be parsed as time.Duration. See time.ParseDuration for the supported format.
func (ConfigValue) Int ¶
func (v ConfigValue) Int() (int, error)
Int tries to parse the ConfigValue as integer. It returns an error if the string can not be parsed as integer.
func (ConfigValue) String ¶
func (v ConfigValue) String() string
type Entries ¶
type Entries []Entry
Entries is a list of [Entry]s.
func (Entries) SplitAtMidnight ¶ added in v0.1.1
SplitAtMidnight creates a list of single-day entries.
The [Entry.ID] will be copied when an Entry is split, causing multiple entries with the same ID to exist. The covered sum of durations does not change.
type Entry ¶
type Entry struct {
ID int `json:"id"`
Start Time `json:"start"`
End Time `json:"end,omitempty"`
Tags []string `json:"tags,omitempty"`
}
Entry is a timewarrior entry that covers a single recorded time interval.
func (*Entry) CurrentEnd ¶ added in v0.1.1
CurrentEnd calculates the actual end of the Entry.
If the Entry is still active, the current time is returned. Otherwise, the recorded time is returned.
type GroupKeyFunc ¶
GroupKeyFunc returns the group key for the given entry.
type GroupValueFunc ¶
GroupValueFunc aggregates entries of a group.
The returned "newResult" is used as input "result" for the next iteration. The value can be a single scalar value or a slice.
type Groups ¶
Groups is a map of any values grouped by a common GroupKey.
func Group ¶
func Group[K GroupKey, V any]( entries Entries, keyFn GroupKeyFunc[K], valueFn GroupValueFunc[V], ) Groups[K, V]
Group aggregates entries into groups.
It returns Groups grouped by GroupKey. The return value of the given GroupKeyFunc is used as mapping key for the processed Entry. The value depends on the return value of the given GroupValueFunc.
Skipping entries is possible by returning the input result unaltered in the GroupValueFunc.
Example (Reduce) ¶
package main
import (
"fmt"
"time"
"github.com/aibor/timewarrior-extensions/twext"
)
func parseTime(s string) twext.Time {
t, err := twext.ParseTime(s)
if err != nil {
panic(err)
}
return t
}
func main() {
entries := twext.Entries{
twext.Entry{
ID: 3,
Start: parseTime("20100629T080000Z"),
End: parseTime("20100629T140000Z"),
},
twext.Entry{
ID: 2,
Start: parseTime("20100629T150000Z"),
End: parseTime("20100629T180000Z"),
},
twext.Entry{
ID: 1,
Start: parseTime("20100630T080000Z"),
End: parseTime("20100630T160000Z"),
},
}
groups := twext.Group(
entries,
func(entry twext.Entry) string {
return entry.Start.Format(time.DateOnly)
},
func(result time.Duration, entry twext.Entry) time.Duration {
return result + entry.Duration()
},
)
for day, group := range groups.Sorted() {
fmt.Println(day, group)
}
}
Output: 2010-06-29 9h0m0s 2010-06-30 8h0m0s
Example (Slices) ¶
package main
import (
"fmt"
"time"
"github.com/aibor/timewarrior-extensions/twext"
)
func parseTime(s string) twext.Time {
t, err := twext.ParseTime(s)
if err != nil {
panic(err)
}
return t
}
func main() {
entries := twext.Entries{
twext.Entry{
ID: 3,
Start: parseTime("20100629T080000Z"),
End: parseTime("20100629T140000Z"),
},
twext.Entry{
ID: 2,
Start: parseTime("20100629T150000Z"),
End: parseTime("20100629T180000Z"),
},
twext.Entry{
ID: 1,
Start: parseTime("20100630T080000Z"),
End: parseTime("20100630T160000Z"),
},
}
groups := twext.Group(
entries,
func(entry twext.Entry) string {
return entry.Start.Format(time.DateOnly)
},
func(result []int, entry twext.Entry) []int {
return append(result, entry.ID)
},
)
for day, group := range groups.Sorted() {
fmt.Println(day, group)
}
}
Output: 2010-06-29 [3 2] 2010-06-30 [1]
func (Groups[K, V]) Sorted ¶
Sorted returns an iterator that iterates the Groups sorted by [GroupKey]s.
func (Groups[K, V]) SortedKeys ¶
func (g Groups[K, V]) SortedKeys() []K
SortedKeys returns the sorted list of [GroupKey]s.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader parses timewarrior extension input data.
The format is expected as described here: https://timewarrior.net/docs/api/#input-format
After creating a NewReader, call Reader.ReadConfig first and then Reader.ReadEntries to get the actual time data.
func NewReader ¶
func NewReader(r io.ReadSeeker) *Reader
NewReader creates a new Reader object.
It does not read any data from the given reader yet.
func (*Reader) ReadConfig ¶
ReadConfig reads the config section of the input.
It must be called before calling Reader.ReadEntries.
func (*Reader) ReadEntries ¶
ReadEntries reads the list of timewarrior entries.
It returns ErrReaderConfigNotConsumed if the configuration section of the input data has not been read yet. Call Reader.ReadConfig beforehand.
type Time ¶
Time extends time.Time with a custom functionality.
func MustParseTime ¶
MustParseTime parses a time from a string in the timewarrior format.
func (*Time) SameDate ¶
SameDate compares two Time values and returns true if they are the same date.
func (*Time) UnmarshalJSON ¶
UnmarshalJSON unmarshals timestamp strings from the timewarrior format.