package main import ( "fmt" "strconv" "strings" "time" "git.bullercodeworks.com/brian/gime-lib" ) func cmdContinueTimer(args []string) int { // Get the last running timer and start a new one with the same tags te, err := getMostRecentTimeEntry() if err != nil { fmt.Println(err.Error()) return 1 } tagColl := te.GetTags() var tags []string for i := 0; i < tagColl.Length(); i++ { tags = append(tags, tagColl.Get(i)) } args = append(args, tags...) return cmdStartTimer(args) } // switchTimer performs a stop on any currently running timers // and starts a new timer with the given arguments func cmdSwitchTimer(args []string) int { loadActiveTimeEntries() tm := time.Now() if timeEntries.Length() > 0 { fmt.Println("Stopped Timers:") } for i := 0; i < timeEntries.Length(); i++ { tmr := timeEntries.Get(i) tmr.SetEnd(tm) if err := gdb.UpdateTimeEntry(tmr); err != nil { fmt.Println(err.Error()) return 1 } fmt.Println(" " + TimerToString(tmr)) } fmt.Println("Started Timer:") return cmdStartTimer(args) } // cmdStartTimer takes a list of arguments and returns the return code // to be passed along to os.Exit func cmdStartTimer(args []string) int { var err error var tm time.Time tagStart := 0 if len(args) > 0 { // Check if the first argument looks like a date/time tm, err = parseFuzzyTime(args[0]) } if len(args) == 0 || err != nil { // Just start it now tm = time.Now() } else { tagStart = 1 } var entry *gime.TimeEntry var timerArgs []string if tagStart < len(args) { timerArgs = args[tagStart:] } tc := new(gime.TagCollection) for i := range timerArgs { tc.Push(timerArgs[i]) } if entry, err = gime.CreateTimeEntry(tm, time.Time{}, tc); err != nil { fmt.Println(err) return 1 } if err = gdb.SaveTimeEntry(entry); err != nil { fmt.Println(err) return 1 } fmt.Println(" " + TimerToString(entry)) return 0 } // cmdStopTimer takes parameters that describe which times to stop func cmdStopTimer(args []string) int { // args[0] should either be a timer id (starting with '@') or 'all' var err error tm := time.Now() actTimers := gdb.LoadTimeEntryCollection(gime.TypeCurrent) var tmr *gime.TimeEntry stopId := "@0" // By default, stop the first timer for i := range args { if args[i] == "all" || args[i][0] == '@' { stopId = args[i] continue } tmpTm, err := parseFuzzyTime(args[i]) if err == nil { // We found a time tm = tmpTm continue } } if stopId != "all" { // Find the timer that we're stopping timerId, err := strconv.Atoi(stopId[1:]) if err != nil { fmt.Println("Error parsing timer id:", err.Error()) return 1 } tmr = actTimers.Get(timerId) if timerId >= actTimers.Length() || timerId < 0 || tmr == nil { fmt.Println("Error finding timer with id:", timerId) return 1 } } stopTimer := func(tmr *gime.TimeEntry, at time.Time) int { tmr.SetEnd(at) if err = gdb.UpdateTimeEntry(tmr); err != nil { fmt.Println(err.Error()) return 1 } fmt.Println("Stopped:", InferTimerDetailString(tmr)) return 0 } if stopId == "all" { var ret int for i := 0; i < actTimers.Length(); i++ { ret += stopTimer(actTimers.Get(i), tm) } if ret > 0 { return 1 // One or more stop operations failed } return 0 } // Just stop the one timer return stopTimer(tmr, tm) } // cmdDeleteTimer takes parameters that describe the timers to be deleted. func cmdDeleteTimer(args []string) int { var err error if len(args) < 1 || args[0][0] != '@' { fmt.Println("Couldn't determine which timer(s) to delete") return 1 } // We've got a timer id to delete timerId, err := strconv.Atoi(args[0][1:]) if err != nil { fmt.Println("Error parsing timer id: " + err.Error()) return 1 } tmr, tp, err := findTimerById(timerId) if err != nil { fmt.Println(err.Error()) return 1 } if gdb.RemoveTimeEntry(tmr.GetUUID()) != nil { fmt.Println("Error removing entry " + gime.TypeToString(tp) + "." + tmr.GetUUID()) return 1 } fmt.Println("Deleted Time Entry: " + TimerToString(tmr)) return 0 } func cmdPrintList(args []string) int { loadActiveAndRecentTimeEntries() useDefaultFilter := true var showIds bool var beg, end time.Time searchTags := []string{} for _, opt := range args { var tmpBeg, tmpEnd time.Time // Check for command modifiers if strings.HasPrefix(opt, ":") { if opt == ":ids" { showIds = true } continue } // Do our best to figure out what timers the user wants to list var err error if strings.Contains(opt, "-") { useDefaultFilter = false pts := strings.Split(opt, "-") if len(pts[0]) > 0 { // This should be the starting date tmpBeg, err = parseFuzzyTime(pts[0]) if err != nil { // We couldn't parse it as a time, // Probably this is just a tag searchTags = append(searchTags, opt) continue } } if len(pts[1]) > 0 { // This should be the ending date tmpEnd, err = parseFuzzyTime(pts[1]) if err != nil { searchTags = append(searchTags, opt) continue } } } else { // Tag filters searchTags = append(searchTags, opt) } if !tmpBeg.IsZero() || !tmpEnd.IsZero() { beg, end = tmpBeg, tmpEnd } } if end.IsZero() { end = time.Now() } // By default, list all entries ending today or still running defaultFilter := func(t *gime.TimeEntry) bool { return t.EndsToday() || t.IsRunning() } timeSpanFilter := func(t *gime.TimeEntry) bool { return t.GetStart().After(beg) && t.GetEnd().Before(end) } tagFilter := func(t *gime.TimeEntry) bool { for i := range searchTags { if !t.HasTag(searchTags[i]) { return false } } return true } compoundFilter := func(t *gime.TimeEntry) bool { // If we didn't get any other filter specifications, just use the default if useDefaultFilter { return defaultFilter(t) } // Otherwise we want to filter timespan and tags return timeSpanFilter(t) && tagFilter(t) } dayStr := "" timers := filterTimerCollection(timeEntries, compoundFilter) _ = dayStr var str string var currId int var err error for i := 0; i < timers.Length(); i++ { wrk := timers.Get(i) oldDayStr := dayStr dayStr = wrk.GetStart().Format("2006/01/02") if dayStr != oldDayStr { str += fmt.Sprintln(dayStr) } id := "" if showIds { if currId, err = findIdOfTimer(wrk); err == nil { id = fmt.Sprintf("%3s", fmt.Sprintf("@%d", currId)) } else { id = "@!" } } str += fmt.Sprintf(" %s %s\n", id, TimerToString(timers.Get(i))) } fmt.Println(str) return 0 } func cmdPrintDetail(args []string) int { fmt.Println("Not implemented yet.") return 1 } func cmdDoArchive(args []string) int { if len(args) == 0 { fmt.Println("Nothing to do") return 1 } bef, err := parseFuzzyTime(args[0]) if err != nil { fmt.Println("Error parsing time") return 1 } ret := 0 fmt.Print("Archive all timers before ", bef) loadActiveAndRecentTimeEntries() for i := 0; i < timeEntries.Length(); i++ { tst := timeEntries.Get(i) if tst.GetEnd().Before(bef) { fmt.Print(".") if err = gdb.ArchiveTimeEntry(tst.GetUUID()); err != nil { fmt.Print("Error archiving entry (", tst.GetUUID(), ")", err.Error()) ret = 1 } } } fmt.Println("Done") return ret }