Use github go-timertxt library
Also more feature add
This commit is contained in:
parent
69e1c959f6
commit
655c4f199e
33
app_state.go
33
app_state.go
@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
timertxt "github.com/br0xen/go-timertxt"
|
||||||
"github.com/br0xen/user-config"
|
"github.com/br0xen/user-config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -109,16 +109,21 @@ func (a *AppState) initialize() {
|
|||||||
a.OpFuncs = make(map[string]func([]string) int)
|
a.OpFuncs = make(map[string]func([]string) int)
|
||||||
a.addOperation("ls",
|
a.addOperation("ls",
|
||||||
[]string{
|
[]string{
|
||||||
"ls - List Timers",
|
"ls [--a] [start] [end] [contexts] [projects] - List Timers",
|
||||||
|
" --a - Include done.txt file",
|
||||||
|
" [start] - List entries after this date",
|
||||||
|
" [end] - List entries before this date",
|
||||||
|
" [@contexts] - List entries with the given contexts",
|
||||||
|
" [+projects] - List entries with the given projects",
|
||||||
},
|
},
|
||||||
a.opListTimers,
|
a.opListTimers,
|
||||||
)
|
)
|
||||||
a.addOperation("lsa",
|
a.addOperation("lsa",
|
||||||
[]string{
|
[]string{
|
||||||
"lsa - The same as 'ls -a'",
|
"lsa [start] [end] [contexts] [projects] - Shortcut for 'ls --a'",
|
||||||
},
|
},
|
||||||
func(args []string) int {
|
func(args []string) int {
|
||||||
return a.opListTimers(append([]string{"-a"}, args...))
|
return a.opListTimers(append([]string{"--a"}, args...))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
a.addOperation("start",
|
a.addOperation("start",
|
||||||
@ -138,12 +143,32 @@ func (a *AppState) initialize() {
|
|||||||
},
|
},
|
||||||
a.opStopTimer,
|
a.opStopTimer,
|
||||||
)
|
)
|
||||||
|
a.addOperation("switch",
|
||||||
|
[]string{
|
||||||
|
"switch [time] [@contexts...] [+projects...] [tag:value...] - Stops all active timers and starts a new one",
|
||||||
|
" with the given arguments",
|
||||||
|
},
|
||||||
|
a.opSwitchTimer,
|
||||||
|
)
|
||||||
|
a.addOperation("archive",
|
||||||
|
[]string{
|
||||||
|
"archive [id] - Archive the timer with the given id",
|
||||||
|
},
|
||||||
|
a.opArchiveTimer,
|
||||||
|
)
|
||||||
a.addOperation("status",
|
a.addOperation("status",
|
||||||
[]string{
|
[]string{
|
||||||
"status - Prints the status of all active timers",
|
"status - Prints the status of all active timers",
|
||||||
},
|
},
|
||||||
a.opStatus,
|
a.opStatus,
|
||||||
)
|
)
|
||||||
|
a.addOperation("mod",
|
||||||
|
[]string{
|
||||||
|
"mod <id> [start=<start>] [end=<end>] [projects=<project,...>] [contexts=<context,...>]",
|
||||||
|
" - Prints the status of all active timers",
|
||||||
|
},
|
||||||
|
a.opModifyTimer,
|
||||||
|
)
|
||||||
a.addOperation("fuzzyparse",
|
a.addOperation("fuzzyparse",
|
||||||
[]string{
|
[]string{
|
||||||
"fuzzyparse [date string] - Parses the passed string and print the RFC3339 result (for testing)",
|
"fuzzyparse [date string] - Parses the passed string and print the RFC3339 result (for testing)",
|
||||||
|
11
helpers.go
11
helpers.go
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
timertxt "github.com/br0xen/go-timertxt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetRoundToDuration() time.Duration {
|
func GetRoundToDuration() time.Duration {
|
||||||
@ -118,7 +118,14 @@ func timerToFriendlyString(t *timertxt.Timer) string {
|
|||||||
for _, v := range t.Projects {
|
for _, v := range t.Projects {
|
||||||
projects += "+" + v + " "
|
projects += "+" + v + " "
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("% 2d. %s - %s [ %s] [ %s] %s", t.Id, start, end, contexts, projects, t.Notes)
|
var dur time.Duration
|
||||||
|
if t.FinishDate.IsZero() {
|
||||||
|
dur = time.Now().Sub(t.StartDate)
|
||||||
|
} else {
|
||||||
|
dur = t.FinishDate.Sub(t.StartDate)
|
||||||
|
}
|
||||||
|
dur = dur.Round(GetRoundToDuration())
|
||||||
|
return fmt.Sprintf("% 2d. %s - %s [ %s] [ %s] %s ( %.2f )", t.Id, start, end, contexts, projects, t.Notes, DurationToDecimal(dur))
|
||||||
}
|
}
|
||||||
|
|
||||||
func friendlyFormatForTime(t time.Time) string {
|
func friendlyFormatForTime(t time.Time) string {
|
||||||
|
2
model.go
2
model.go
@ -4,7 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
timertxt "github.com/br0xen/go-timertxt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *AppState) SetTimerFinished(id int, end time.Time) error {
|
func (a *AppState) SetTimerFinished(id int, end time.Time) error {
|
||||||
|
21
screen.go
21
screen.go
@ -1,6 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
termbox "github.com/nsf/termbox-go"
|
termbox "github.com/nsf/termbox-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,15 +49,19 @@ func readUserInput(e chan termbox.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshList(e chan termbox.Event) {
|
func checkForUpdate(e chan termbox.Event) {
|
||||||
/*
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(5 * time.Minute)
|
time.Sleep(time.Minute)
|
||||||
app.LoadTasklist()
|
// Check if the on-disk tasklist has changed
|
||||||
app.LoadDoneList()
|
//app.LoadTasklist()
|
||||||
e <- termbox.Event{Type: termbox.EventNone}
|
//app.LoadDoneList()
|
||||||
|
if false {
|
||||||
|
e <- termbox.Event{
|
||||||
|
Type: termbox.EventError,
|
||||||
|
Err: errors.New("List changed elsewhere"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
timertxt "github.com/br0xen/go-timertxt"
|
||||||
"github.com/br0xen/termbox-util"
|
"github.com/br0xen/termbox-util"
|
||||||
termbox "github.com/nsf/termbox-go"
|
termbox "github.com/nsf/termbox-go"
|
||||||
)
|
)
|
||||||
|
155
timer_ops.go
155
timer_ops.go
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
timertxt "github.com/br0xen/go-timertxt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *AppState) opStatus(args []string) int {
|
func (a *AppState) opStatus(args []string) int {
|
||||||
@ -33,21 +33,33 @@ func (a *AppState) opStatus(args []string) int {
|
|||||||
* By default, only list Today
|
* By default, only list Today
|
||||||
*/
|
*/
|
||||||
func (a *AppState) opListTimers(args []string) int {
|
func (a *AppState) opListTimers(args []string) int {
|
||||||
var start, end time.Time
|
var includeArchive bool
|
||||||
var err error
|
var err error
|
||||||
|
start := time.Time{}
|
||||||
|
end := time.Now()
|
||||||
|
var contextFilters []string
|
||||||
|
var projectFilters []string
|
||||||
|
|
||||||
|
var allFilters []func(timertxt.Timer) bool
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
contextFilters, args = getContextsFromSlice(args)
|
||||||
|
projectFilters, args = getProjectsFromSlice(args)
|
||||||
|
}
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
if args[0] == "--a" {
|
if args[0] == "--a" {
|
||||||
start = time.Time{}
|
includeArchive = true
|
||||||
end = time.Now()
|
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
if len(args) > 0 {
|
||||||
if start, err = parseFuzzyTime(args[0]); err != nil {
|
if start, err = parseFuzzyTime(args[0]); err != nil {
|
||||||
y, m, d := time.Now().Date()
|
y, m, d := time.Now().Date()
|
||||||
start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location())
|
start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location())
|
||||||
} else {
|
} else {
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
}
|
}
|
||||||
|
if len(args) > 0 {
|
||||||
if end, err = parseFuzzyTime(args[0]); err != nil {
|
if end, err = parseFuzzyTime(args[0]); err != nil {
|
||||||
y, m, d := time.Now().Date()
|
y, m, d := time.Now().Date()
|
||||||
end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location())
|
end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location())
|
||||||
@ -56,8 +68,51 @@ func (a *AppState) opListTimers(args []string) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if includeArchive {
|
||||||
|
if err = a.LoadDoneList(); err != nil {
|
||||||
|
fmt.Println("Error loading done.txt entries")
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
list := a.TimerList.GetTimersInRange(start, end)
|
list := a.TimerList.GetTimersInRange(start, end)
|
||||||
|
if includeArchive {
|
||||||
|
*list = append(*list, (*a.DoneList.GetTimersInRange(start, end))...)
|
||||||
|
}
|
||||||
|
if len(contextFilters) > 0 {
|
||||||
|
allFilters = append(allFilters, func(t timertxt.Timer) bool {
|
||||||
|
for _, v := range contextFilters {
|
||||||
|
v = strings.TrimPrefix(v, "@")
|
||||||
|
if !t.HasContext(v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(projectFilters) > 0 {
|
||||||
|
allFilters = append(allFilters, func(t timertxt.Timer) bool {
|
||||||
|
for _, v := range projectFilters {
|
||||||
|
v = strings.TrimPrefix(v, "+")
|
||||||
|
if !t.HasProject(v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
doFilters := func(t timertxt.Timer) bool {
|
||||||
|
for _, v := range allFilters {
|
||||||
|
if !v(t) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we made it all the way down here, it matches
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
list = list.Filter(doFilters)
|
||||||
|
|
||||||
dayTotals := make(map[string]time.Duration)
|
dayTotals := make(map[string]time.Duration)
|
||||||
for _, v := range *list {
|
for _, v := range *list {
|
||||||
dur := v.FinishDate.Sub(v.StartDate)
|
dur := v.FinishDate.Sub(v.StartDate)
|
||||||
@ -149,7 +204,27 @@ func (a *AppState) opStopTimer(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppState) opSwitchTimer(args []string) int {
|
func (a *AppState) opSwitchTimer(args []string) int {
|
||||||
return 0
|
var timerIds []int
|
||||||
|
var err error
|
||||||
|
end := time.Now()
|
||||||
|
// Stop all running timers and start a new one with the given args
|
||||||
|
for _, v := range *a.TimerList.GetActiveTimers() {
|
||||||
|
timerIds = append(timerIds, v.Id)
|
||||||
|
}
|
||||||
|
fmt.Print("Stopping ", timerIds, "\n")
|
||||||
|
for _, v := range timerIds {
|
||||||
|
var stopped *timertxt.Timer
|
||||||
|
if stopped, err = a.TimerList.GetTimer(v); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = a.SetTimerFinished(v, end); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Println("Stopped Timer:", timerToFriendlyString(stopped))
|
||||||
|
}
|
||||||
|
return a.opStartTimer(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppState) opArchiveTimer(args []string) int {
|
func (a *AppState) opArchiveTimer(args []string) int {
|
||||||
@ -186,7 +261,73 @@ func (a *AppState) opArchiveTimer(args []string) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppState) opState(args []string) int {
|
func (a *AppState) opModifyTimer(args []string) int {
|
||||||
|
var timer *timertxt.Timer
|
||||||
|
var contexts, projects []string
|
||||||
|
id, err := strconv.Atoi(args[0])
|
||||||
|
if err != nil {
|
||||||
|
// We didn't have a timer id, so try to modify the first active timer
|
||||||
|
if len(*a.TimerList.GetActiveTimers()) > 0 {
|
||||||
|
timer = &(*a.TimerList.GetActiveTimers())[0]
|
||||||
|
} else {
|
||||||
|
// And we don't have any active timers
|
||||||
|
fmt.Println("No active timers, 'id' must be provided.")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = args[1:]
|
||||||
|
if timer, err = a.TimerList.GetTimer(id); err != nil {
|
||||||
|
fmt.Printf("Error getting timer %d\n", id)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var start, end time.Time
|
||||||
|
|
||||||
|
for _, v := range args {
|
||||||
|
pts := strings.Split(v, "=")
|
||||||
|
switch pts[0] {
|
||||||
|
case "beginning", "start":
|
||||||
|
if start, err = parseFuzzyTime(pts[1]); err != nil {
|
||||||
|
fmt.Println("Error parsing start time.")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
case "stop", "finish", "end":
|
||||||
|
if end, err = parseFuzzyTime(pts[1]); err != nil {
|
||||||
|
fmt.Println("Error parsing end time.")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
case "project", "projects":
|
||||||
|
projects = strings.Split(pts[1], ",")
|
||||||
|
case "context", "contexts":
|
||||||
|
contexts = strings.Split(pts[1], ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(contexts) > 0 {
|
||||||
|
for k := range contexts {
|
||||||
|
contexts[k] = strings.TrimPrefix(contexts[k], "@")
|
||||||
|
}
|
||||||
|
timer.Contexts = contexts
|
||||||
|
}
|
||||||
|
if len(projects) > 0 {
|
||||||
|
for k := range projects {
|
||||||
|
projects[k] = strings.TrimPrefix(projects[k], "+")
|
||||||
|
}
|
||||||
|
timer.Projects = projects
|
||||||
|
}
|
||||||
|
if !start.IsZero() {
|
||||||
|
timer.StartDate = start
|
||||||
|
}
|
||||||
|
if !end.IsZero() {
|
||||||
|
timer.FinishDate = end
|
||||||
|
timer.Finished = true
|
||||||
|
}
|
||||||
|
fmt.Println("Modified Timer:")
|
||||||
|
fmt.Println(timerToFriendlyString(timer))
|
||||||
|
|
||||||
|
if err := a.WriteList(); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user