Use github go-timertxt library

Also more feature add
This commit is contained in:
Brian Buller 2019-02-26 09:41:00 -06:00
parent 69e1c959f6
commit 655c4f199e
6 changed files with 220 additions and 40 deletions

View File

@ -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,64 +109,89 @@ 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",
[]string{ []string{
"start [time] [@contexts...] [+projects...] [tag:value...]", "start [time] [@contexts...] [+projects...] [tag:value...]",
" - Start a timer with the given details", " - Start a timer with the given details",
" If the first argument looks like a time,", " If the first argument looks like a time,",
" the timer will be started then (past or future)", " the timer will be started then (past or future)",
}, },
a.opStartTimer, a.opStartTimer,
) )
a.addOperation("stop", a.addOperation("stop",
[]string{ []string{
"stop [time] - Stops the current timer", "stop [time] - Stops the current timer",
" If the first argument looks like a time,", " If the first argument looks like a time,",
" the timer will be stopped then (past or future)", " the timer will be stopped then (past or future)",
}, },
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)",
}, },
a.opFuzzyParse, a.opFuzzyParse,
) )
a.addOperation("--reinit", a.addOperation("--reinit",
[]string{"--reinit - Reset all Configuration Settings"}, []string{"--reinit - Reset all Configuration Settings"},
func(args []string) int { func(args []string) int {
a.initializeConfig() a.initializeConfig()
return 0 return 0
}, },
) )
a.addOperation("-h", a.addOperation("-h",
[]string{"-h - Print this message"}, []string{"-h - Print this message"},
a.opPrintUsage, a.opPrintUsage,
) )
a.addOperation("help", a.addOperation("help",
[]string{"help - Print this message"}, []string{"help - Print this message"},
a.opPrintUsage, a.opPrintUsage,
) )
a.addOperation("--h", a.addOperation("--h",
[]string{"--h - Print this message"}, []string{"--h - Print this message"},
a.opPrintUsage, a.opPrintUsage,
) )
a.directory = a.config.Get("directory") a.directory = a.config.Get("directory")

View File

@ -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 {

View File

@ -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 {

View File

@ -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(time.Minute)
time.Sleep(5 * time.Minute) // Check if the on-disk tasklist has changed
app.LoadTasklist() //app.LoadTasklist()
app.LoadDoneList() //app.LoadDoneList()
e <- termbox.Event{Type: termbox.EventNone} if false {
e <- termbox.Event{
Type: termbox.EventError,
Err: errors.New("List changed elsewhere"),
}
} }
*/ }
} }
/* /*

View File

@ -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"
) )

View File

@ -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:]
}
}
if len(args) > 0 {
if start, err = parseFuzzyTime(args[0]); err != nil {
y, m, d := time.Now().Date()
start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location())
} else { } else {
if start, err = parseFuzzyTime(args[0]); err != nil { args = args[1:]
y, m, d := time.Now().Date() }
start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location()) if len(args) > 0 {
} else {
args = args[1:]
}
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
} }