package main import ( "fmt" "strconv" "strings" "time" timertxt "github.com/br0xen/go-timertxt" ) func (a *AppState) opStatus(args []string) int { if len(*a.TimerList.GetActiveTimers()) == 0 { fmt.Println("No timers running") return 0 } var currDur time.Duration for _, v := range *a.TimerList { if v.ActiveToday() { currDur += v.Duration() } } d := currDur.Round(GetRoundToDuration()) fmt.Printf("%s ( %.2f hrs )\n", time.Now().Format(time.Stamp), DurationToDecimal(d)) for _, v := range *a.TimerList.GetActiveTimers() { fmt.Println(timerToFriendlyString(&v)) } return 0 } /** * List timers for a given time span * By default, only list Today */ func (a *AppState) opListTimers(args []string) int { var includeArchive bool 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 args[0] == "--a" { includeArchive = true 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 { args = args[1:] } if len(args) > 0 { if end, err = parseFuzzyTime(args[0]); err != nil { y, m, d := time.Now().Date() end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location()) } else { args = args[1:] } } } 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) 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) for _, v := range *list { dur := v.FinishDate.Sub(v.StartDate) if v.FinishDate.IsZero() { dur = time.Now().Sub(v.StartDate) } dayTotals[v.StartDate.Format("2006/01/02")] += dur } var oldDayStr, dayStr string for _, v := range *list { oldDayStr = dayStr dayStr = v.StartDate.Format("2006/01/02") if dayStr != oldDayStr { wrkDur := dayTotals[dayStr].Round(GetRoundToDuration()) fmtStr := dayStr + " ( %.2f )\n" fmt.Printf(fmtStr, DurationToDecimal(wrkDur)) } fmt.Println(" " + timerToFriendlyString(&v)) } return 0 } func (a *AppState) opStartTimer(args []string) int { var contexts, projects, strTags []string t := timertxt.NewTimer() if len(args) > 0 { if start, err := parseFuzzyTime(args[0]); err == nil { t.StartDate = start args = args[1:] } } contexts, args = getContextsFromSlice(args) projects, args = getProjectsFromSlice(args) strTags, args = getAdditionalTagsFromSlice(args) for _, v := range contexts { t.Contexts = append(t.Contexts, strings.TrimPrefix(v, "@")) } for _, v := range projects { t.Projects = append(t.Projects, strings.TrimPrefix(v, "+")) } for _, v := range strTags { tgPts := strings.Split(v, ":") t.AdditionalTags[tgPts[0]] = tgPts[1] } a.TimerList.AddTimer(t) if err := a.WriteList(); err != nil { fmt.Println(err.Error()) return 1 } fmt.Println("Started: ", TimerToString(t)) return 0 } func (a *AppState) opStopTimer(args []string) int { var err error var wrk time.Time end := time.Now() id := -1 if len(args) > 0 { if wrk, err = parseFuzzyTime(args[0]); err != nil { id, err = strconv.Atoi(args[0]) } else { end = wrk args = args[1:] } } fmt.Println("Stopping at : " + end.Format(time.RFC3339)) var timerIds []int if id == -1 { for _, v := range *a.TimerList.GetActiveTimers() { timerIds = append(timerIds, v.Id) } } else { timerIds = append(timerIds, id) } for _, v := range timerIds { var stopped *timertxt.Timer if stopped, err = a.TimerList.GetTimer(v); err != nil { fmt.Println(err.Error()) } if err = a.SetTimerFinished(v, end); err != nil { fmt.Println(err.Error()) continue } fmt.Println("Stopped Timer:", timerToFriendlyString(stopped)) } if err = a.WriteList(); err != nil { fmt.Println(err.Error()) return 1 } return 0 } func (a *AppState) opSwitchTimer(args []string) int { 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 { if len(args) > 0 { for _, v := range args { var id int var timer *timertxt.Timer var err error if strings.HasPrefix(v, "@") { // We're archiving by context v = strings.TrimPrefix(v, "@") fmt.Println("Archiving by context:", v) timers := a.TimerList.GetTimersWithContext(v) fmt.Println("Found timers: ", len(*timers)) for _, tmr := range *timers { if tmr.Finished { if err = a.archiveTimer(tmr.Id); err != nil { fmt.Printf("Error archiving timer %d\n", tmr.Id) continue } fmt.Println(a.getDoneTimerString(tmr)) } else { fmt.Println("Refusing to archive running timer:", tmr.Id) } } } else if strings.HasPrefix(v, "+") { // We're archiving by projcet v = strings.TrimPrefix(v, "+") fmt.Println("Archiving by project:", v) timers := a.TimerList.GetTimersWithProject(v) fmt.Println("Found timers: ", len(*timers)) for _, tmr := range *timers { if tmr.Finished { if err = a.archiveTimer(tmr.Id); err != nil { fmt.Printf("Error archiving timer %d\n", tmr.Id) continue } fmt.Println(a.getDoneTimerString(tmr)) } else { fmt.Println("Refusing to archive running timer:", tmr.Id) } } } else { // I guess we're archiving by timer id if id, err = strconv.Atoi(v); err != nil { fmt.Printf("Invalid id given: %s\n", v) return 1 } if timer, err = a.TimerList.GetTimer(id); err != nil { fmt.Printf("Error getting timer %d\n", id) return 1 } if timer.Finished { if err = a.archiveTimer(id); err != nil { fmt.Printf("Error archiving timer %d\n", id) return 1 } fmt.Println(a.getDoneTimerString(*timer)) } else { fmt.Println("Refusing to archive running timer:", timer.Id) } } } } else { for _, v := range *a.TimerList { if v.Finished { if err := a.archiveTimer(v.Id); err != nil { fmt.Printf("Error archiving task %d\n", v.Id) return 1 } fmt.Println(a.getDoneTimerString(v)) } } } return 0 } func (a *AppState) opRemoveTimer(args []string) int { if len(args) == 0 { fmt.Println("No timer id given") return 1 } id, err := strconv.Atoi(args[0]) if err != nil { fmt.Println("Invalid timer id given: " + args[0]) } t, err := a.TimerList.GetTimer(id) if err != nil { fmt.Println("Error getting timer with id: " + args[0]) return 1 } if err = a.TimerList.RemoveTimerById(id); err != nil { fmt.Println("Error Removing Timer: " + err.Error()) return 1 } fmt.Println("Timer removed") fmt.Println(TimerToString(t)) if err := a.WriteList(); err != nil { fmt.Println(err.Error()) return 1 } return 0 } 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 } func (a *AppState) opFuzzyParse(args []string) int { if len(args) > 0 { if start, err := parseFuzzyTime(args[0]); err == nil { fmt.Println(start.Format(time.RFC3339)) } else { fmt.Println(err.Error()) } } return 0 } func (a *AppState) opConfig(args []string) int { if len(args) == 0 { fmt.Println("Config Keys:") for _, v := range a.config.GetKeyList() { fmt.Println(" " + v) } } else { if args[0] == "timerpath" { fmt.Println(a.directory + a.fileTimer) } else { fmt.Println(a.config.Get(args[0])) } } return 0 } func (a *AppState) opPrintUsage(args []string) int { for _, v := range a.ValidOperations { for _, vv := range v { fmt.Println(" " + vv) } fmt.Println("") } return 0 }